基础背包问题(01,完全,多重)

01背包:

有n 种不同的物品,每一种物品一件,每个物品有两个属性,wei重量(体积),val 价值,现在给一个容量为 V 的背包,问最多可带走多少价值的物品。

完全背包:

在01背包的基础上,如果物品不计件数,就是每个物品无限件的话,求出结果。

多重背包:

在01背包的基础上,每一件物品的件数是一定的(给出的),求出结果。


01背包:

状态转移方程(默认求最大价值):dp[j]=dp[j-wei[i]]+val[i]>dp[j]?dp[j-wei[i]]+val[i]:dp[j]

for (int i=0; i<n; i++){
    for (int j=V; j>=wei[i]; j--){        
              int t = dp[j-wei[i]]+val[i];
              dp[j] =dp[j]>t?dp[j]:t;
        }
}
完全背包:
为了累加效果,所以从前向后遍历:
for (int i=0; i<n; i++){
    for (int j=wei[i]; j<=V; j++){        
              int t = dp[j-wei[i]]+val[i];
              dp[j] =dp[j]>t?dp[j]:t;
        }
}
多重背包:
把每一中物品的个数用二进制原理展开,转成01背包处理:
多重背包的二进制转化原理:
把一个数字展开成二进制,我们可以发现一个数字可以由小于他的1,10,10,1……组成。有一个误区,例子:10转化成二进制后:1010,设c=10, 如果直接用for(int i=1; i<=c; i<<=1) 枚举我们将得到1, 10, 100, 1000 这几个二进制数,存在结果大于10的组合(如1111)。想要将多重背包转化成01背包,就必须保证得到的数字的任意组合小于等于10。所以枚举时有这样的改进:
f or(int i=1;i<=c;i<<=1){
     //---
    c-=i;
}
if(c>0){ //--   }
得到的数字是1,10,100,11。前三个数字的组合结果包含了0——7,最后一个数字是3,那么结果就是0——10。刚好满足条件。

另外,如果DP的初始化是0,那么得出结果是V可以不用完的,也能是用完的。当初始化为负无穷小 -inf,dp[0]=0时,结果是V刚好用完的。(看看代码就能明白)

hdu 1114  Piggy-Bank(多重背包取最小)

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long LL;
LL n,V,wei[505],val[505],dp[10005];
LL work(){
    for(int i=0;i<n;i++){
        for(int j=wei[i];j<=V;j++){
            int t=dp[j-wei[i]]+val[i];
            dp[j]=t<dp[j]?t:dp[j];
        }
    }
    return dp[V];
}
int main()
{
    //freopen("cin.txt","r",stdin);
    int t;
    cin>>t;
    while(t--){
        LL E,F;
        scanf("%lld%lld",&E,&F);
        V=F-E;
        memset(dp,0x3f,sizeof(dp));
        dp[0]=0;
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%d%d",&val[i],&wei[i]);
        }
        LL ans=work();
        if(ans>=0x3f3f3f3f) printf("This is impossible.\n");
        else printf("The minimum amount of money in the piggy-bank is %lld.\n",ans);
    }
    return 0;
}


hdu 2191  悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(简单多重背包)

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int wei[505],val[505],dp[105];
int n,V;
int main()
{
    int t,m;
    cin>>t;
    while(t--){
        scanf("%d%d",&V,&m);
        int w,v,c;
        n=0;
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&w,&v,&c);
            for(int j=1;j<=c;j<<=1){
                wei[n]=w*j;
                val[n++]=v*j;
                c-=j;
            }
            if(c>0) {
                wei[n]=w*c;
                val[n++]=v*c;
            }
        }
        memset(dp,0,sizeof(dp));
        int ans=0;
        for(int i=0;i<n;i++){
            for(int j=V;j>=wei[i];j--){
                int t=dp[j-wei[i]]+val[i];
                dp[j]=dp[j]>t?dp[j]:t;
                ans=ans>dp[j]?ans:dp[j];
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

hdu 1171  Big Event in HDU (wei=val 多重背包)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=3e5+10;
int wei[400],dp[N],cnt;
int main()
{
    //freopen("cin.txt","r",stdin);
    int n;
    while(cin>>n&&(n>0)){
        cnt=0;
        int w,c;
        int V=0;
        for(int i=0;i<n;i++){
            scanf("%d%d",&w,&c);
            V=V+w*c;
            for(int j=1;j<=c;j<<=1){
                wei[cnt++]=w*j;
                c-=j;
            }
            if(c>0) wei[cnt++]=w*c;
        }
        int V2=V/2;
        memset(dp,0,sizeof(dp));
        for(int i=0;i<cnt;i++){
            for(int j=V2;j>=wei[i];j--){
                int t=dp[j-wei[i]]+wei[i]; //price同时是重量和价值
                dp[j]=t>dp[j]?t:dp[j];
            }
        }
        int ans2=dp[V2],ans1=V-ans2;
        printf("%d %d\n",ans1,ans2);
    }
    return 0;
}

hdu 1864   最大报销额(wei=val浮点01背包)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=3e6+10;
int wei[N],dp[N];
bool check(char ch){
    if(ch=='A'||ch=='B'||ch=='C') return true;
    return false;
}
int main()
{
    //freopen("cin.txt","r",stdin);
    double q;
    int n,m;
    while(cin>>q>>n&&n){
        int cnt=0;
        for(int i=0;i<n;i++){
            scanf("%d",&m);
            char s1,s2;
            double p;
            int sum=0,aa=0,bb=0,cc=0;
            bool tag=1;  //attention: 单项(类)物品的价值不得超过600元.
            for(int j=0;j<m;j++){
                scanf(" %c%c%lf",&s1,&s2,&p);
                int x=int(p*100);
                sum+=x;
                if(check(s1)==false)  tag=0;
                if(tag){
                    if(s1=='A') aa+=x;
                    else if(s1=='B')  bb+=x;
                    else cc+=x;
                }
            }
            if(aa<=60000&&bb<=60000&&cc<=60000&&sum<=100000&&tag) wei[cnt++]=sum;
        }
        memset(dp,0,sizeof(dp));
        int qq=int(q*100);
        for(int i=0;i<cnt;i++){
            for(int j=qq;j>=wei[i];j--){
                int t=dp[j-wei[i]]+wei[i]; //价格既有重量的性质又有价值的性质
                dp[j]=t>dp[j]?t:dp[j];
            }
        }
        printf("%.2lf\n",dp[qq]/100.0);
    }
    return 0;
}

hdu 4508  湫湫系列故事——减肥记I  (简单完全背包)

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const LL N=105,M=1e5+10;
LL n,V;
LL wei[N],val[N],dp[M];
LL work(){
    memset(dp,0,sizeof(dp));
    for(int i=0;i<n;i++){
        for(int j=wei[i];j<=V;j++){
            LL t=dp[j-wei[i]]+val[i];
            dp[j]=dp[j]>t?dp[j]:t;
        }
    }
    return dp[V];
}
int main()
{
    //freopen("cin.txt","r",stdin);
    while(cin>>n){
        for(int i=0;i<n;i++){
            scanf("%I64d%I64d",&val[i],&wei[i]);
        }
        scanf("%I64d",&V);
        memset(dp,0,sizeof(dp));
        printf("%I64d\n",work());
    }
    return 0;
}





 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值