金明的预算方案

Description

金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的。

如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有0个、1个或2个附件。附件不再有从属于自己的附件。金明想买的东西很多,肯定会超过妈妈限定的N元。于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。他还从因特网上查到了每件物品的价格(都是10元的整数倍)。他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

Analysis

第一次遇到的依赖性背包问题。

如果取消附件的限制,那么这题可以用01背包解决。加上附件之后,相当于1个主件变成了4件物品(附件的选择导致),且此4件物品互相冲突。因为4常数非常小..所以在计算到此主件组时,只要枚举4种情况,找出最优情况就行了。

但是如果附件变多了,组合数太多,为2^n,该怎么办呢?不难发现主件组中各种组合进行了多次冗余计算,可以想到先给主件组中的组合来一发01背包,求出各种价格下的最大获得值,这样就把所有的组合化成了价格数个物品。当然这题无需优化。

Code

#include <bits/stdc++.h>

int n,m,dp[32001],id[101];
std::vector <int> gift[101];

struct node{
    int v,w;
}th[101];

int main(){
    freopen("budget.in","r",stdin);
    freopen("budget.ans","w",stdout);
    std::cin>>n>>m;
    for(int i=1;i<=m;i++){
        int q;
        std::cin>>th[i].v>>th[i].w>>q;
        th[i].w*=th[i].v;
        if(!q)id[++id[0]]=i;
        else gift[q].push_back(i);
    }
    m=id[0];
    for(int i=1;i<=m;i++)
        for(int j=n;j>=th[id[i]].v;j--){
            int v=th[id[i]].v;
            int w=th[id[i]].w;
            dp[j]=std::max(dp[j],dp[j-v]+w);
            if(gift[id[i]].empty())continue;
            for(int k=0;k<gift[id[i]].size();k++){
                int s=gift[id[i]][k];
                if(j>=th[s].v+v)
                    dp[j]=std::max(dp[j],dp[j-v-th[s].v]+w+th[s].w);
            }
            if(gift[id[i]].size()>1){
                int s0=gift[id[i]][0];
                int s1=gift[id[i]][1];
                if(j>=th[s0].v+th[s1].v+v)
                    dp[j]=std::max(dp[j],dp[j-v-th[s0].v-th[s1].v]+w+th[s0].w+th[s1].w);
            }
        }
    std::cout<<dp[n]<<std::endl;
    return 0;
}

转载于:https://www.cnblogs.com/qswx/p/9492515.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值