POJ 1946(三维DP)

http://poj.org/problem?id=1946
  题意:有N头奶牛,要跑D圈,每头奶牛的初始能量为E,每头牛每分钟可以跑任意圈,除领跑的奶牛外,每跑x圈,消耗能量为x,领跑的奶牛消耗的能量为x*x,能量消耗尽的奶牛随时退场,问至少有一头奶牛能去到终点所用的最短时间。
  思路:dp[i][j][k]表示前i-1头奶牛都已耗尽能量或者中途离场,现在第i头奶牛已经跑了j圈且已经消耗了k的能量,假设,当前奶牛继续以l圈/分钟的速度跑一分钟,则状态dp[i][j+l][k+l*l] = dp[i][j][k] + 1,(j+l <= D,j+l*l <= E),当然,状态是否转移,要判断转移后所消耗时间是否更小。其次,每头奶牛可以在任何时候随时退场,轮到下一头奶牛领跑,所以还有一个特别点的转移方式,dp[i+1][j][j] = dp[i][j][k],主要理解的是能量的变化,因为第i+1头奶牛刚刚领跑,之前一共跟跑了j圈,所以已经消耗的能量是j,而且换领队是不需要消耗时间的,当然是否转移也是要判断一下大小的,详见代码。
#include<iostream>
#include<cstring>
#include<cstdio>
#define inf 1e9
using namespace std;
 
int dp[30][110][110];
// dp[i][j][k]:第i头奶牛领跑,共跑了j圈,共消耗能量k,的最少时间
int main() {
    int N, E, D;
    while(cin>>N>>E>>D) {
        for(int i = 0; i <= N; ++i) {
            for(int j = 0; j <= D; ++j)
                for(int k = 0; k <= E; ++k)
                    dp[i][j][k] = inf;
        }
        dp[1][0][0] = 0;   // 初始条件
        for(int i = 1; i <= N; ++i) {
            for(int j = 0; j <= D; ++j) {
                for(int k = 0; k <= E; ++k) {
                    // 枚举i、j、k,当dp[i][j][k]有意义时,进行状态转移
                    if(dp[i][j][k] == inf) continue;
                    for(int l = 1; l + j <= D && l*l + k <= E; ++l)
                    // 枚举奶牛以每分钟跑l圈的速度,注意总圈数和初始能量的限制即可
                        dp[i][j+l][k+l*l] = min(dp[i][j+l][k+l*l], dp[i][j][k] + 1);
                    // 这里还有一个重要的转移! 当前奶牛退出比赛轮到下一头奶牛领跑。
                    // 注意能量变化,下头奶牛已经跑了j圈,初始能量消耗也应该为j
                    dp[i+1][j][j] = min(dp[i+1][j][j], dp[i][j][k]);
                }
            }
        }
        // 找出跑完N圈的最少时间,如果跑不完dp[N][D][0] = 0,不需特判
        int Min = inf;
        for(int i = 0; i <= E; ++i)
            Min = min(Min, dp[N][D][i]);
        cout<<Min<<endl;
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章