这道题WA了N次,看了下别人的题解,终于对动态数组有了更深的认识,这些DP题算是没白做。题目主要是对负数的处理上,类似交流电加上直流偏执,将整体DP的范围加上一个固定偏移进行背包即可,需要注意的是:
(1)应用动态数组就是要在一维上实现两维的状态转移,复用一维状态位实现二维更新。应用到题目中,就体现在如果参数是正数,就应该从MAX到MIN背包,如果参数时负数,就从MIN到MAX背包,使得每一次状态转移时,对应位上的值不是已经覆盖了的值。
时间上可以优化的细节:
(2)背包优化细节:对于s <= 0 && t <= 0的点,肯定不会选中,所以可以直接跳过。
(3)初始化优化细节:由于动态数组长度很大,但对于每一组输入交流的幅度却不一定有这么大,而最终的取值范围却是在交流的峰峰之间,所以初始化时我们只需对交流的峰峰值之间这个范围进行初始化。
空间上可以优化的细节:
(4)边输入边背包
容易遗忘的细节:
(5)在背包之后取最优解时,注意题目要求TS和TF都要非负。
#include <cstdio>
#include <algorithm>
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;
}