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 ;} 
posted on 2012-04-28 21:56  追逐.  阅读(320)  评论(0编辑  收藏  举报