背包问题(二)
多重背包
对于一个容量为V的背包,我们有N种物品,每种num[i]个,消耗cost[i],价值val[i],求最大价值和
实际上,多重背包在01背包与完全背包之间
我们可以将num[i]个物品分成1个,2个…num[i]个
在这num[i]种选择中选择一种并且每种选择数量为一
其实这就是让我们选择num[i]个物品选几个
那么这个问题就被我们转化成01背包了
这可真棒!
三维代码//看到这里你有没有明白什么
#include<bits/stdc++.h>
using namespace std;
const int maxn=505,maxm=6005;
int v[maxn],w[maxn],s[maxn];
int dp[maxm];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d%d%d",&v[i],&w[i],&s[i]);
for(int i=1;i<=n;i++){
for(int j=m;j>=0;j--){
for(int k=0;k<=s[i];k++){
if(j>=k*v[i])
dp[j]=max(dp[j],dp[j-k*v[i]]+w[i]*k);
}
}
}
printf("%d",dp[m]);
return 0;
}
二进制优化代码
后续更新时间优化做法
例题 砝码称重
这道题我们的物品就是这6种砝码
我们可以求出组成x克的方案数,其它基本同模板
#include<bits/stdc++.h>
using namespace std;
const int maxn=10;
int a[maxn];
int d[maxn]={0,1,2,3,5,10,20};
int dp[1005];
int main()
{
for(int i=1;i<=6;i++)scanf("%d",&a[i]);
dp[0]=1;
for(int i=1;i<=6;i++){
if(a[i]==0)continue;
for(int j=1000;j>=0;j--){
for(int k=0;k<=a[i];k++){
if(j>=d[i]*k)
dp[j]+=dp[j-d[i]*k];
}
}
}
int ans=0;
for(int i=1;i<=1000;i++){
if(dp[i]>0)ans++;
}
printf("Total=%d",ans);
return 0;
}
分组背包
一个容量为V的背包,现在有n件物品,重量是W[i],价值是C[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求最大价值总和。