zoukankan      html  css  js  c++  java
  • HDU-3236Gift Hunting(多背包问题)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3236

    题目链接:某人有两张卡,卡上的钱不能合并消费,买东西的时候物品有两个属性,一个是必须买的,还有一个不是必须买的,同一样物品用不同的卡消费相同并且只能购买一次,我们需要最大的价值(即happy值),你还有一张优惠券进行免费消费一次。

    Sample Input

    3 2 4
    3 10 1
    2 10 0
    5 100 0
    5 80 0
    3 2 4
    3 10 1
    2 10 0
    5 100 0
    5 80 1
    0 0 0

    Sample Output

    Case 1: 120
    
    Case 2: 100

    emmm,两张卡,不能合并消费,那么也就是2个背包问题了,多了个免费券,那么我们再开一维来记录券的使用情况就OK了,那么状态转移方程也不难写出来

    对于必须买的物品,我们直接往里面塞:

    int tot=0,pre=0;
    memset(dp,0,sizeof dp);
    for (int i=1; i<=special; i++) {
        pre=tot;//必须把前i-1个都拿了才能作为转移状态
        tot+=sp[i].h;
        for (int j=v1; j>=0; j--) {
            for (int k=v2; k>=0; k--) {
                if (dp[j][k][0]==pre) dp[j][k][1]=tot;
                if (j-sp[i].p>=0) {
                    if (dp[j-sp[i].p][k][1]==pre) dp[j][k][1]=tot;
                    if (dp[j-sp[i].p][k][0]==pre) dp[j][k][0]=tot;
                }
                if (k-sp[i].p>=0) {
                    if (dp[j][k-sp[i].p][1]==pre) dp[j][k][1]=tot;
                    if (dp[j][k-sp[i].p][0]==pre) dp[j][k][0]=tot;
                }
            }
        }
    }

    那么如果能够买完所有特殊物品,则背包最大容量的价值一定会等于所有特殊物品的价值,也就是$dp[v1][v2][1]==tot$

    接下来就是一个比较有点技巧的操作,我们将没有装满特殊物品的状态打上标记,用来表示该状态不能作为转移状态,然后开始对普通物品跑多个01背包了。其具体写法和特殊物品差不多,只不过多了个标记的判断而已。

    以下是AC代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    struct node
    {
        int p,h;
    }sp[320],nom[320];
    int dp[510][60][5];
    
    int main()
    {
        int v1,v2,n;
        int Case=0;
        while (scanf ("%d%d%d",&v1,&v2,&n)){
            if (!v1 && !v2 && !n) return 0;
            int special=0,nomall=0;
            for (int i=1; i<=n; i++){
                int p,h,s;
                scanf ("%d%d%d",&p,&h,&s);
                if (s) sp[++special]=node{p,h};
                else nom[++nomall]=node{p,h};
            }
            int tot=0,pre=0;
            memset(dp,0,sizeof dp);
            for (int i=1; i<=special; i++){
                pre=tot;//必须把前i-1个都拿了才能作为转移状态
                tot+=sp[i].h;
                for (int j=v1; j>=0; j--){
                    for (int k=v2; k>=0; k--){
                        if (dp[j][k][0]==pre) dp[j][k][1]=tot;
                        if (j-sp[i].p>=0){
                            if (dp[j-sp[i].p][k][1]==pre) dp[j][k][1]=tot;
                            if (dp[j-sp[i].p][k][0]==pre) dp[j][k][0]=tot;
                        }
                        if (k-sp[i].p>=0){
                            if (dp[j][k-sp[i].p][1]==pre) dp[j][k][1]=tot;
                            if (dp[j][k-sp[i].p][0]==pre) dp[j][k][0]=tot;
                        }
                    }
                }
            }
            if (dp[v1][v2][1]<tot) {printf("Case %d: -1
    
    ",++Case);  continue;}
            for (int i=0; i<=v1; i++)
                for (int j=0; j<=v2; j++)
                    for (int k=0; k<=1; k++)
                        if (dp[i][j][k]!=tot) dp[i][j][k]=-1;//没有装满特殊物品的状态不能作为转移状态
    
            for (int i=1; i<=nomall; i++){
                for (int j=v1; j>=0; j--){
                    for (int k=v2; k>=0; k--){
                        if (dp[j][k][0]!=-1) dp[j][k][1]=max(dp[j][k][1],dp[j][k][0]+nom[i].h);
                        for (int o=0; o<=1; o++){
                            if (dp[j][k][o]==-1) continue;
                            if (j-nom[i].p>=0){
                                if (dp[j-nom[i].p][k][o]!=-1) dp[j][k][o]=max(dp[j][k][o],dp[j-nom[i].p][k][o]+nom[i].h);
                            }
                            if (k-nom[i].p>=0){
                                if (dp[j][k-nom[i].p][o]!=-1) dp[j][k][o]=max(dp[j][k][o],dp[j][k-nom[i].p][o]+nom[i].h);
                            }
                        }
                    }
                }
            }
            printf("Case %d: %d
    
    ",++Case,dp[v1][v2][1]);  
        }
        return 0;
    }
    路漫漫兮
  • 相关阅读:
    【转载】用XML和XSLT来生成静态的HTML页面
    【转载】Lambda表达式(Lambda Expressions)
    [转]打领带的十种方法
    读书笔记
    【转载】用手机的朋友进来看看吧,终身受益啊!!!
    SQL查询出重复出现的数据
    技巧三:字符串格式化
    【Vegas原创】页面自动跳转代码收集
    【Vegas原创】我写的一个安装windowsService的BAT
    【Vegas原创】ASP.NET读取Excel,并以邮件正文方式和附件方式发送实例
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/13263622.html
Copyright © 2011-2022 走看看