背包问题主要是背模板,这里收录了一些模板

一些复杂的背包问题(如泛化物品)未收录

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背包 我们可以看做是这些都是只能取一次的多重背包,所以他们是一类)

 

posted on 2020-05-22 15:35  月下诺  阅读(314)  评论(0编辑  收藏  举报

Live2D