POJ-2184(背包 + 动态数组,给交流电加个直流偏执)

这道题WA了N次,看了下别人的题解,终于对动态数组有了更深的认识,这些DP题算是没白做。题目主要是对负数的处理上,类似交流电加上直流偏执,将整体DP的范围加上一个固定偏移进行背包即可,需要注意的是:

(1)应用动态数组就是要在一维上实现两维的状态转移,复用一维状态位实现二维更新。应用到题目中,就体现在如果参数是正数,就应该从MAX到MIN背包,如果参数时负数,就从MIN到MAX背包,使得每一次状态转移时,对应位上的值不是已经覆盖了的值。

时间上可以优化的细节:

(2)背包优化细节:对于s <= 0 && t <= 0的点,肯定不会选中,所以可以直接跳过。

(3)初始化优化细节:由于动态数组长度很大,但对于每一组输入交流的幅度却不一定有这么大,而最终的取值范围却是在交流的峰峰之间,所以初始化时我们只需对交流的峰峰值之间这个范围进行初始化。

空间上可以优化的细节:

(4)边输入边背包

容易遗忘的细节:

(5)在背包之后取最优解时,注意题目要求TS和TF都要非负。


#include 
#include 
using namespace std;
#define INF     99999999

const int BIAS = 100 * 1000;
int N, dp[200 * 1000 + 1];//dp[i + BIAS] is maximum TS, when TF = i

int main()
{
    int i, s, f, maxi, mini;
    while(scanf("%d", &N) == 1){
    //initialize
        maxi = N * 1000;
        mini = -maxi;
        for(i = mini; i <= maxi; ++i) dp[i + BIAS] = -INF;
        dp[0 + BIAS] = 0;
    //DP while input
        while(N--){
            scanf("%d %d", &s, &f);
            if(s <= 0 && f <= 0) continue;//cut off, which definitely won't be chosen
            if(f >= 0){//dp from MAX to MIN
                for(i = maxi - f; i >= mini; --i){
                    if(dp[i + BIAS] > -INF)
                        dp[i + f + BIAS] = max(dp[i + f + BIAS], dp[i + BIAS] + s);
                }
            }
            else{//dp from MIN to MAX
                for(i = mini - f; i <= maxi; ++i){
                    if(dp[i + BIAS] > -INF)
                        dp[i + f + BIAS] = max(dp[i + f + BIAS], dp[i + BIAS] + s);
                }
            }
        }
    //pick maximum dp[i + BIAS] + i, where i >= 0 && dp[i + BIAS] >= 0
        s = 0;
        for(i = 0; i <= maxi; ++i){
            if(dp[i + BIAS] >= 0) s = max(s, dp[i + BIAS] + i);
        }
        printf("%d\n", s);
    }
    return 0;
}


你可能感兴趣的:(DP,每天A一道题)