题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4501
解题思路:
三维背包,设置dp[i][j][k]代表有i块钱,有j个积分和k个免费物品的时候,可以得到的最大价值。
则对于当前物品,我有两种选择:
第一种:不买
第二种:买
如果选择买又分了三种情况,
1.用钱买。 dp[i-钱][j][k] + 价值
2.用积分买。 dp[i][j-积分][k] + 价值
3.免费拿。 dp[i][j][k-1] + 价值
联合第一种情况:dp[i][j][k],从四个数中取最大值。
然后我就按01背包做了,我做的时候是考虑装第t个物品的时候,钱数大于该物品的价格,积分
也大于该物品的积分,结果发现跑的时候答案不对,我才意识到,如果该人未带钱,可以用积分
买或免费拿,当人没有积分,可以用钱买或免费拿,当商场不给k个免费机会的时候,可以用钱和
积分,而我上面的根本没法弄他们是0的情况。所以每层循环最后都是从容量到0,然后后续的
操作中我们可以判断,如果钱还够,就考虑用钱买的情况,否则不考虑,如果积分还够考虑用
积分买的情况,否则不考虑,如果免费拿的机会还没用完,即考虑免费拿的情况,否则不考虑该
情况。
总复杂度:100*100*100*50.稳过。
AC代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int maxn = 105;
int N,v1,v2,K;
int price[maxn],score[maxn],value[maxn];
int dp[maxn][maxn][maxn/2];
int Max(int a,int b,int c,int d) {
int ans = a;
if(ans < b)
ans = b;
if(ans < c)
ans = c;
if(ans < d)
ans = d;
return ans;
}
int main() {
while(~scanf("%d%d%d%d",&N,&v1,&v2,&K)) {
for(int i = 1; i <= N; i++) {
scanf("%d%d%d",&price[i],&score[i],&value[i]);
}
memset(dp,0,sizeof(dp));
int x1,x2,x3,x4;
for(int i = 1; i <= N; i++) {
for(int j = v1; j >= 0; j--) {
for(int k = v2; k >= 0; k--) {
for(int t = K; t >= 0; t--) {
x1 = dp[j][k][t];
if(j >= price[i])
x2 = dp[j-price[i]][k][t] + value[i];
else
x2 = x1;
if(k >= score[i])
x3 = dp[j][k-score[i]][t] + value[i];
else
x3 = x1;
if(t>0)
x4 = dp[j][k][t-1] + value[i];
else
x4 = x1;
dp[j][k][t] = Max(x1,x2,x3,x4);
}
}
}
}
printf("%d\n",dp[v1][v2][K]);
}
return 0;
}