zoj 2972 Hurdles of 110m (DP)

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 ;} 

你可能感兴趣的:(ZOJ)