DP-四种背包问题模板总结【01背包、完全背包、多重背包、混合背包】
//01背包
#include <bits/stdc++.h>
using namespace std;
int n,v,w,c,dp[1010];//dp[i]表示装入物品的质量为i时能获得的最大价值
int main()
{
cin>>v>>n;//v为背包容量,n为物品数量
for(int i=1;i<=n;i++)
{
cin>>w>>c;//w为每个物品重量,c为每个物品价值
for(int j=v;j>=w;j--)//背包容量从大到小遍历
dp[j]=max(dp[j],dp[j-w]+c);//选择不放入背包dp[j]还是放入背包dp[j-w]+c,更新为最大的dp[j]
}
printf("%d\n",dp[v]);//装入物品的质量为v时能获得的最大价值
return 0;
}
//完全背包
#include <bits/stdc++.h>
using namespace std;
int n,v,w,c,dp[100010];
int main()
{
cin>>v>>n;
for(int i=1;i<=n;i++)
{
cin>>w>>c;
for(int j=w;j<=v;j++)//背包容量从小到大遍历,这里与01背包循环顺序相反!
dp[j]=max(dp[j],dp[j-w]+c);
}
printf("%d\n",dp[v]);
return 0;
}
//多重背包
//多重背包可以转化为01背包求解,可以把每次输入的s件物品分解为2的幂次和,
//比如说s=7,那么s=1+2+4,相应地就把多重背包转化为
//w[1]=1 * w0,c[1]=1 * c0,
//w[2]=2 * w0,c[2]=2 * c0,
//w[3]=4 * w0,c[3]=4 * c0,
//这就是所谓的多重背包的二进制优化。
//当然你也可以把s件一件一件的分解(s=1+1+…+1),用这种朴素的做法,数据大就容易超时,不推荐使用。
#include <bits/stdc++.h>
using namespace std;
int n,v,w,c,dp[100010];
int main()
{
cin>>v>>n;
for(int i=1;i<=n;i++)
{
cin>>w>>c;
for(int j=w;j<=v;j++)//背包容量从小到大遍历,这里与01背包循环顺序相反!
dp[j]=max(dp[j],dp[j-w]+c);
}
printf("%d\n",dp[v]);
return 0;
}
//混合背包
//混合背包:有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包)。
//这样看来混合背包其实就是01背包+多重背包+完全背包,而多重背包又可以转化为01背包,
//所以要解决混合背包的问题可以分别按多重背包和完全背包的方式处理。
#include <bits/stdc++.h>
using namespace std;
int n,v,s,k,w0,c0,cnt,rest,w[100010],c[100010],dp[100010];
int main()
{
cin>>v>>n;
while(n--)
{
cin>>w0>>c0>>s;//重量为w0,价值为c0的物品有s件
if(s==0)//按完全背包处理
{
for(int j=w0;j<=v;j++)
dp[j]=max(dp[j],dp[j-w0]+c0);
}
else//把多重背包转化为01背包,把s分解为2的幂次和,保存到w数组和c数组中,之和再按01背包处理
{
rest=s;k=1;//rest是剩余的物品数,k是从小到大的2的幂次
while(rest>=k)//rest<k时结束,结束时按2的幂次恰好分完则rest=0,否则0<rest<k,要继续处理剩余的rest
{
w[++cnt]=w0*k;
c[cnt]=c0*k;
rest=rest-k;
k=k*2;
}
if(rest>0){w[++cnt]=w0*rest;c[cnt]=c0*rest;}
}
}
for(int i=1;i<=cnt;i++)//按01背包处理
for(int j=v;j>=w[i];j--)
dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
printf("%d\n",dp[v]);
return 0;
}
浙公网安备 33010602011771号