http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2972
i为当前第几段,j为跑完第i段剩余的体力。第i段有三种跑法可选:
第一种要消耗f1的体力,所以保证j+f1<=m。dp[i][j] = min(dp[i][j], dp[i-1][j+f1]+t1) ;
第二种不消耗体力。 dp[i][j] = min(dp[i][j], dp[i-1][j]+t2) ;
第三种增加f2的体力,保证j-f2>=0。dp[i][j] = min(dp[i][j], dp[i-1][j-f2]+t3) ;
还有一种情况需要单独考虑,即以第三种方式跑,使得体力值积累大于了m,以m为准。那么它的前一个状态便不为dp[i-1][j-f2]了,应该为dp[i-1][m-1...m-f2]。所以要加个循环单独筛出这种情况的最小值。
code:
#include<cstdio>
const int max = 1e+9 ;
int dp[120][120] ;
int min(int a, int b){
return a>b?b:a ;
}
int main(){
int t, i, j, n, m, t1, t2, t3, f1, f2 ;
scanf("%d", &t) ;
while(t--){
scanf("%d%d", &n, &m) ;
for(i=0; i<=n; i++)
for(j=0; j<=m; j++)
dp[i][j] = max ;
dp[0][m] = 0 ;
for(i=1; i<=n; i++){
scanf("%d%d%d%d%d", &t1, &t2, &t3, &f1, &f2) ;
for(j=0; j<=m; j++){
if(j+f1<=m)
dp[i][j] = min(dp[i][j], dp[i-1][j+f1]+t1) ;
dp[i][j] = min(dp[i][j], dp[i-1][j]+t2) ;
if(j-f2>=0)
dp[i][j] = min(dp[i][j], dp[i-1][j-f2]+t3) ;
}
for(j=1; j<=f2; j++)//单独考虑
if(m-j>=0)
dp[i][m] = min(dp[i][m], dp[i-1][m-j]+t3) ;
}
int x = max ;
for(j=0; j<=m; j++)
if(dp[n][j]<x) x = dp[n][j] ;
printf("%d\n", x) ;
}
return 0 ;}
const int max = 1e+9 ;
int dp[120][120] ;
int min(int a, int b){
return a>b?b:a ;
}
int main(){
int t, i, j, n, m, t1, t2, t3, f1, f2 ;
scanf("%d", &t) ;
while(t--){
scanf("%d%d", &n, &m) ;
for(i=0; i<=n; i++)
for(j=0; j<=m; j++)
dp[i][j] = max ;
dp[0][m] = 0 ;
for(i=1; i<=n; i++){
scanf("%d%d%d%d%d", &t1, &t2, &t3, &f1, &f2) ;
for(j=0; j<=m; j++){
if(j+f1<=m)
dp[i][j] = min(dp[i][j], dp[i-1][j+f1]+t1) ;
dp[i][j] = min(dp[i][j], dp[i-1][j]+t2) ;
if(j-f2>=0)
dp[i][j] = min(dp[i][j], dp[i-1][j-f2]+t3) ;
}
for(j=1; j<=f2; j++)//单独考虑
if(m-j>=0)
dp[i][m] = min(dp[i][m], dp[i-1][m-j]+t3) ;
}
int x = max ;
for(j=0; j<=m; j++)
if(dp[n][j]<x) x = dp[n][j] ;
printf("%d\n", x) ;
}
return 0 ;}