解题思路
动态规划数组dp[i],存储最终人品值为i时所能获得的最大收益是多少。由于人品可能是负数,所以讲初始的人品值+10000,使得人品值一直是正数,相应的门槛值也要增加10000。在初始化的时候将每个dp[i]的值设为最小值-1000000,再将dp[10000]赋为0.之后每输入一个事件(即三个值),就更新一次dp数组,其状态转移方程为dp[j + rp] = max(dp[j + rp] , dp[j] + pro);
注意
在更新dp数组的时候一定要注意循环的顺序。
1)当rp变化为正数时,要从门槛值递减遍历到下界
2)当rp变化为负数时,要从门槛值递增遍历到上界
如果反过来遍历,会导致有些人品值达不到但却会被更新,例如一开始人品是10000,这时有一个事件为1 10 -1。如果是从下界递增遍历,那么首先当j=0时,会更新dp[1] = -1,而当j=1时,又会更新dp[2] = max(dp[2] , dp[1] +1) = -2,然而实际上dp[2]的值是不存在的(或者说是初始化的最小值)。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#define minimum -100000000
#define C 10000
using namespace std;
int rp , con , pro;
int dp[4*C];
int solve(){
int N , result;
int i , j , k ,t ;
cin >> N;
result = 0;
for( i = 0 ; i <= 2*C ; i ++)
dp[i] = minimum;
dp[C] = 0;
for( i = 1 ; i <= N ; i ++)
{
cin >> rp >> con >> pro;
con += C;
if( rp > 0 ){
for( j = min ( 2*C - rp , con ) ; j >= 0 ; j --)
dp[j + rp] = max(dp[j + rp] , dp[j] + pro);
}else{
for( j = max(-rp , con); j <= 2*C ; j ++)
dp[j + rp] = max(dp[j + rp] , dp[j] + pro);
}
}
for( i = 0 ; i <= 2*C ; i ++)
result = max(result , dp[i]);
cout << result << endl;;
return 0;
}
int main(){
int T , i;
cin >> T;
for(i = 1 ; i <= T ; i ++)
solve();
return 0;
}