题目
思路
本质就是个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;
}