[动态规划] 洛谷P1064 金明的预算方案 (01背包)

题目

LP1064

思路

本质就是个01背包,不过是每个状态的决策数从两个变成了五个,只是复杂些而已。
五种决策:
1.不拿本物体。
2.只拿本物体。
3.只拿本物体与附物体1。
4.只拿本物体与附物体2。
5.拿本物体,附物体1与附物体2。
其它与简化版相同。

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;

const int maxn = 60 + 5;
const int maxx = 32000 + 100;
struct item {
    int K, V, W, F1V, F2V, F1W, F2W;
    item() :F1V(0), F2V(0), F1W(0), F2W(0) {}
}A[maxn];
int N, M, d[maxn][maxx];

int main() {
    scanf("%d%d", &M, &N);
    int x = 1, V, W, P;
    _for(i, 0, N) {
        scanf("%d%d%d", &V, &W, &P);
        if (P == 0) {
            A[x].K = i+1; A[x].V = V; A[x].W = W; x++;
        }
        else {
            int j;
            for (j = 1; j < x; j++) if (A[j].K == P) break;
            if (A[j].F1V == 0) {
                A[j].F1V = V; A[j].F1W = W;
            }
            else {
                A[j].F2V = V; A[j].F2W = W;
            }
        }
    }
    x--;

    _rep(i, 1, x)
        _rep(j, 0, M) {
        d[i][j] = (i == 1 ? 0 : d[i - 1][j]);  // 决策1
        if (j + A[i].V <= M)  // 决策2 
            d[i][j] = max(d[i][j], d[i - 1][j + A[i].V] + A[i].V * A[i].W);
        if (A[i].F1V != 0 && j + A[i].F1V + A[i].V <= M)   // 决策3 
            d[i][j] = max(d[i][j], d[i - 1][j + A[i].F1V + A[i].V] + A[i].V * A[i].W + A[i].F1V * A[i].F1W);
        if (A[i].F2V != 0 && j + A[i].F2V + A[i].V <= M)   // 决策4
            d[i][j] = max(d[i][j], d[i - 1][j + A[i].F2V + A[i].V] + A[i].V * A[i].W + A[i].F2V * A[i].F2W);

        if (A[i].F1V != 0 && A[i].F2V != 0 && j + A[i].F1V + A[i].F2V + A[i].V <= M) // 决策5
            d[i][j] = max(d[i][j], d[i - 1][j + A[i].F1V + A[i].F2V + A[i].V] +
                A[i].V * A[i].W + A[i].F1V * A[i].F1W + A[i].F2V * A[i].F2W);
    }

    int ans = 0;
    _rep(i, 0, M) ans = max(ans, d[x][i]);
    printf("%d\n", ans);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/icecab/article/details/80768383