POJ 1964 Cow Cycling(黑书 + DP经典 + 背包)

题意:

现在有 N 头奶牛, 每头奶牛的能量是E, 现在要奶牛们只要有一头完成跑D圈就完成任务。

但是每次都要由一头奶牛领跑, 没有能量的奶牛可以退场或继续跟跑, 但是带头的奶牛体力消耗是: x*x laps/min, 跟跑的是x laps/min。

现在要你计算出最短时间内完成任务。 (黑书 158 奶牛转圈)

思路:

1. dp[i][d][e] 表示第 i 只奶牛跑了 d 圈且能量消耗为 e 时,所需的最小分钟;

2. 针对第 i 只奶牛是否领跑,又展开了讨论,如果不领跑,注意到一个性质:跑了多少圈就消耗多少能量,则有: dp[i][d][d] = dp[i-1][d][e];

3. 如果第 i 只奶牛领跑,则考虑它领跑的速度是多少以及这 d 圈有多少圈是领跑的,可以利用完全背包的策略把代码简化为 O(N*D*E);

   dp[i][d][] = min(dp[i][d][], dp[i][d-k][] + 1); 相当于体积为 1 的物品价值为 1,看成完全背包,时间规模减少一维;

4. 一开始我把转移方程式理解成了:dp[i][e][d] 表示第 i 只奶牛消耗能量值为 e 时且跑了 d 圈,所需的最小分钟,没有利用到完全背包的性质,见代码2 ;

 

#include <iostream>

#include <algorithm>

using namespace std;



const int MAXN = 110;

const int INFS = 0x3fffffff;

int dp[25][MAXN][MAXN], N, E, D;



int main() {

    while (~scanf("%d%d%d", &N, &E, &D)) {

        for (int i = 1; i <= N; i++)

            for (int d = 0; d <= D; d++) 

                for (int e = 0; e <= E; e++)

                    dp[i][d][e] = INFS;

        dp[1][0][0] = 0;

        for (int i = 1; i <= N; i++) {

            for (int d = 1; d <= D; d++) {

                for (int e = 1; e <= E; e++) {

                    for (int k = 1; k*k <= e && k <= d; k++) 

                        dp[i][d][e] = min(dp[i][d][e], dp[i][d-k][e-k*k] + 1);

                    dp[i+1][d][d] = min(dp[i+1][d][d], dp[i][d][e]);

                }

            }

        }

        int ans = INFS;

        for (int e = 1; e <= E; e++)

            ans = min(ans, dp[N][D][e]);

        printf("%d\n", ans);

    }

    return 0;

}

代码2 (110ms) :

#include <iostream>

#include <algorithm>

using namespace std;



const int MAXN = 110;

const int INFS = 0x3fffffff;

int dp[25][MAXN][MAXN], N, E, D;



int main() {

    while (~scanf("%d%d%d", &N, &E, &D)) {

        for (int i = 1; i <= N; i++)

            for (int e = 0; e <= E; e++)

                for (int d = 0; d <= D; d++)

                    dp[i][e][d] = INFS;

        dp[1][0][0] = 0;

        for (int i = 1; i <= N; i++) {

            for (int e = 1; e <= E; e++) {

                for (int d = 1; d <= D; d++) {

                    for (int x = 1; ; x++) {

                        int coste = x * x, costd = x;

                        if (coste > e || costd > d) break;

                        for (int k = 1; k*coste <= e && k*costd <= d; k++)

                            dp[i][e][d] = min(dp[i][e][d], dp[i][e-coste*k][d-costd*k] + k);

                    }

                    dp[i+1][d][d] = min(dp[i+1][d][d], dp[i][e][d]);

                }

            }

        }

        int ans = INFS;

        for (int i = 1; i <= N; i++)

            for (int e = 1; e <= E; e++)

                ans = min(ans, dp[i][e][D]);



        printf("%d\n", ans);

    }

    return 0;

}
 

你可能感兴趣的:(poj)