背包问题精讲2018-08-09

第一道题:https://www.luogu.org/problemnew/show/P1060
这道题就是一道非常的01背包模板,不过需要注意到题目的条件还需要乘上重要性,也就是价值=原价值*重要度,其他的就按照01背包模板照打即可。
附上代码吧:

#include <bits/stdc++.h>
using namespace std;
const int maxn=100000+20;
int a[maxn],w[maxn],v[maxn],f[maxn];
int main(){
    int n,m,k;
	cin>>m>>n;
	for(int i=1;i<=n;i++){
		 cin>>v[i]>>k;
		 w[i]=k*v[i];
    }
    for(int i=1;i<=n;i++)
		for(int j=m;j>=v[i];j--)
			f[j]=max(f[j],f[j-v[i]]+w[i]);
	cout<<f[m];
	return 0;
}

第二道题:https://www.luogu.org/problemnew/show/P1064
这一道题比上一道题难度明显增加了许多,而且,这道题的背包有依赖性了,也就是以来背包,思路:
价值=原价值*重要度不变,但后面多了个附件的条件,也就是说,每一个主件都最多可以拥有2个附件,则输入时需要优先存储每一个附件的归属情况,这里我用二位数组存储,那么,读入的代码就是这样的:

    //q1是第一个附件的存储情况,q2是第二个附件的存储情况,v是价值,p是重要度,q是是否为附件,若是,又为谁的附件。
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>v[i]>>p[i]>>q[i];
        if(!q[i]){
            w[i]=v[i];
            c[i]=v[i]*p[i];
        }
        else{
            q1[q[i]][0]++;
            q1[q[i]][q1[q[i]][0]]=v[i];
            q2[q[i]][q1[q[i]][0]]=v[i]*p[i];
        }
    }

接下来,在DP的循环里面,我们也需要考虑几种情况:

1.若是第一个附件
2.若是第二个附件
3.如果即是第一个附件又是第二个附件

所以,附上重要部分的代码:

    for(int i=1;i<=m;i++)
        for(int j=n;j>=w[i];j--){
            f[j]=max(f[j],f[j-w[i]]+c[i]);
            if(j-w[i]-q1[i][1]>=0)
                f[j]=max(f[j],f[j-w[i]-q1[i][1]]+c[i]+q2[i][1]);
            if(j-w[i]-q1[i][2]>=0)
                f[j]=max(f[j],f[j-w[i]-q1[i][2]]+c[i]+q2[i][2]);
            if(j-w[i]-q1[i][1]-q1[i][2]>=0)
                f[j]=max(f[j],f[j-w[i]-q1[i][1]-q1[i][2]]+c[i]+q2[i][1]+q2[i][2]);
         }

最后,附上完整代码:

#include <iostream>
const int maxn=1000+50;
using namespace std;
int n,m,f[maxn],v[maxn],p[maxn],q[maxn],w[maxn],c[maxn],q1[maxn][maxn],q2[maxn][maxn];
int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>v[i]>>p[i]>>q[i];
        if(!q[i]){
            w[i]=v[i];
            c[i]=v[i]*p[i];
        }
        else{
            q1[q[i]][0]++;
            q1[q[i]][q1[q[i]][0]]=v[i];
            q2[q[i]][q1[q[i]][0]]=v[i]*p[i];
        }
    }
    for(int i=1;i<=m;i++)
        for(int j=n;j>=w[i];j--){
            f[j]=max(f[j],f[j-w[i]]+c[i]);
            if(j-w[i]-q1[i][1]>=0)
                f[j]=max(f[j],f[j-w[i]-q1[i][1]]+c[i]+q2[i][1]);
            if(j-w[i]-q1[i][2]>=0)
                f[j]=max(f[j],f[j-w[i]-q1[i][2]]+c[i]+q2[i][2]);
            if(j-w[i]-q1[i][1]-q1[i][2]>=0)
                f[j]=max(f[j],f[j-w[i]-q1[i][1]-q1[i][2]]+c[i]+q2[i][1]+q2[i][2]);
         }
     cout<<f[n];
     return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值