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

kedebug

Department of Computer Science and Engineering,

Shanghai Jiao Tong University

E-mail: kedebug0@gmail.com

GitHub: http://github.com/kedebug

-------------------------------------------------------

原文地址:https://www.cnblogs.com/kedebug/p/3006457.html