HDU 4501:小明系列故事——买年货

题目链接: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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值