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


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