背包问题主要是背模板,这里收录了一些模板
一些复杂的背包问题(如泛化物品)未收录
01背包问题:
无优化
for(int i=1;i<=n;i++)
{
for(int c=0;c<=m;c++)
{
f[i][c]=f[i-1][c];
if(c>=w[i])
f[i][c]=max(f[i][c],f[i-1][c-w[i]]+v[i]);
}
}
一维数组优化:
for(int i=1;i<=n;i++)
{
for(int c=m;c>=0;c--)
{
if(c>=w[i])
f[c]=max(f[c],f[c-w[i]]+v[i]);
}
}
更进一步的常数优化:
for(int i=1;i<=n;i++)
{
sumw+=w[i];
bound=max(m-sumw,w[i]);
for(int c=m;c>=bound;c--)
{
if(c>=w[i])
f[c]=max(f[c],f[c-w[i]]+v[i]);
}
}
完全背包问题:
for(int i=1;i<=n;i++)
{
for(int c=0;c<=m;c++)
{
if(c>=w[i])
f[c]=max(f[c],f[c-w[i]]+v[i]);
}
}
多重背包问题:
for(int i=1;i<=n;i++)
for(int j=m;j>=1;j--)
for(int k=0;k<=c[i];k++)
{
if(dp[j]-k*s[i]<0)
break;
dp[j]=max(dp[j],dp[j-k*s[i]]+k*c[i]);
}
其实三种背包的区别在于数量的多少
所谓的01背包就是只能取一次,而完全背包是可以去无数次,多重背包对于每一件物品的数量有一个限定,所以我们要加入一个特判
if(dp[j]-k*s[i]<0) break;
没有什么技巧可言,对于数组的建立也是取决于个人喜好
下面是几道背包的例题(版子)
http://ybt.ssoier.cn:8088/problem_show.php?pid=1267

这是01背包的版子
#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxm=201,maxn=31;
int m,n;
int w[maxn],c[maxn];
int dp[maxm];
int main()
{
cin>>m>>n;
for(int i=1;i<=n;i++)
cin>>w[i]>>c[i];
for(int i=1;i<=n;i++)
for(int j=m;j>=w[i];j--)
dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
cout<<dp[m];
return 0;
}
http://ybt.ssoier.cn:8088/problem_show.php?pid=1268

完全背包的版子
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define itn int
using namespace std;
int dp[10000],w[10000],c[10000];
itn n,m;
int main()
{
cin>>m>>n;
for(int i=1;i<=n;i++)
{
cin>>w[i]>>c[i];
}
for(int i=1;i<=n;i++)
for(itn j=w[i];j<=m;j++)
dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
cout<<"max="<<dp[m]<<endl;
return 0;
}
http://ybt.ssoier.cn:8088/problem_show.php?pid=1269

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define itn int
#define q 10000
using namespace std;
int dp[q],c[q],w[q],v[q];
int n,m;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>w[i]>>c[i]>>v[i];//价格 价值 数量
for(int i=1;i<=n;i++)
for(int j=m;j>=0;j--)
for(itn k=0;k<=v[i];k++)
{if(j-k*w[i]<0) break;
dp[j]=max(dp[j],dp[j-k*w[i]]+k*c[i]); }
cout<<dp[m];
return 0;
}
http://ybt.ssoier.cn:8088/problem_show.php?pid=1270

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define itn int
#define q 10000
using namespace std;
itn f[q],w[q],c[q],v[q];
int main()
{
int m,n;
cin>>m>>n;
for(int i=1;i<=n;i++)
cin>>w[i]>>c[i]>>v[i];
for(int i=1;i<=n;i++)
{if(v[i]==0)
{
for(itn j=w[i];j<=m;j++)
f[j]=max(f[j],f[j-w[i]]+c[i]);
}
else
for(itn j=1;j<=v[i];j++)
for(itn k=m;k>=w[i];k--)
f[k]=max(f[k],f[k-w[i]]+c[i]);
}
cout<<f[m];
return 0;
}
最后的混合背包意思是对于物品的拿取的数量还是有要求的,有的可以无限拿(完全背包) 有的只能拿一次(01背包)
还有的只能拿指定的数量(多重背包)
对于混合背包 我们只需要对于他的数量进行判断({if(v[i]==0)) 那么便是完全背包;else 便是01或是多重(BB一句对于01背包 我们可以看做是这些都是只能取一次的多重背包,所以他们是一类)
浙公网安备 33010602011771号