zoukankan      html  css  js  c++  java
  • POJ3612 Telephone Wire 动态规划

    这题的状态推倒极富想象力,原来写过的代码又忘了如何去写了......

    题意:其实就和以前做过的一道我要长高一模一样,给定N个数字,现在要求连续的两个数字之差的绝对值乘以C最小,每个数字可以变大,变大所带来的开销为变量的平方.

      状态方程为 dp[i][j] = min(dp[i-1][k] + C*|j-k| + (j-H[i]) ^ 2)

      if (j >= k)   dp[i][j] = min(dp[i-1][k] -  C*k) +C*j + (j-H[i])^2
      if (j <= k)   dp[i][j] = min(dp[i-1][k] + C*k) - C*j + (j-H[i])^2

      状态的是通过 i-1 行来推导第 i 行的状态,这里的技巧在于

      for (int j  = H[i-1]; j <= 100; ++j)  Min = min(Min, dp[i-1][j] - C*k)

      这个循环来遍历 i-1 行的所有合法高度,配合下面那条语句,就能够得到满足当前的j>Min中的k
      也就是Min中的保留的最小值时的k一定是小于等于当前我们枚举到的j,也就满足了第一个式子,后面就只需要判定一下当前的j是否能够有H[i]得到,也就是j >= H[i]

      for (int j = 100; j >= H[i]; --j) Min = min(Min, dp[i-1][j] + C*k) 

      这里的边界条件不是H[i-1],因为我们要求的推导的第i行的状态数应该是从H[i] - 100因此要把边界控制成H[i]

    代码如下:

    #include <cstdlib>
    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #define INF 0x3f3f3f3f
    #define MAXN 100000
    using namespace std;
    
    int N, C, seq[MAXN+5];
    int dp[2][105]; // dp[i][j]表示从到第i个数字高度为j时的最小值
    
    inline int pow2(int x) {
        return x * x;
    }
    
    int DP() {
        int Min;
        memset(dp, 0x3f, sizeof (dp));
        for (int j = seq[1]; j <= 100; ++j) { // 只能够增加 
            dp[1][j] = pow2(j-seq[1]);
        }
        for (int i = 2; i <= N; ++i) {
            int t = i&1;    
            Min = INF;
            for (int j = 1; j <= 100; ++j) dp[t][j] = INF; // 每次都需要初始化 
            for (int j = seq[i-1]; j <= 100; ++j) { // 枚举上一层的状态,来推倒当前层的状态
            // 从小到大枚举i-1层,则Min中保存的值对应的i-1层的高度一定小于j
                Min = min(Min, dp[!t][j]-C*j);
                if (j >= seq[i]) {
                    dp[t][j] = min(dp[t][j], Min + C*j + pow2(j-seq[i]));
                }
            }
            Min = INF;
            for (int j = 100; j >= seq[i]; --j) { // 保证所有合法的状态都予以求值
                Min = min(Min, dp[!t][j]+C*j);
                if (j >= seq[i]) {
                    dp[t][j] = min(dp[t][j], Min - C*j + pow2(j-seq[i]));
                }
            }
        }
        Min = INF;
        for (int i = seq[N]; i <= 100; ++i) {
            Min = min(Min, dp[N&1][i]);
        }
        return Min;
    }
    
    int main() {
        while (scanf("%d %d", &N, &C) == 2) {
            for (int i = 1; i <= N; ++i) {
                scanf("%d", &seq[i]);
            }
            printf("%d\n", DP());
        }
        return 0;    
    }
  • 相关阅读:
    内置对象 和 DropDownList时间年月日的三级联动
    复合控件 ispostback 跨页面传值
    webform简单控件和Repeater的使用
    初步认识ASP.NET WebForm
    WinForm Timer控件,三级联动[省,市,区]
    进程 线程 用户控件
    窗体容器MDI
    对话框控件 MessageBox.Show()用法补充 打开新窗体的3中模式
    winform窗体移动和阴影API
    PS学习笔记
  • 原文地址:https://www.cnblogs.com/Lyush/p/2853227.html
Copyright © 2011-2022 走看看