背包整理

背包整理

01背包

01背包顾名思义,就是0与1放或不放的问题。首先挂上最重要的状态转移方程
f[i][v]=max(f[i][v-w[i]]+c[i],f[i-1][v]);
V表示不超过V的重量。f[i][v]也就是第I件物品

#include<bits/stdc++.h>
using namespace std;
int a[20001],c[20001],b[30001],m,n;
int main()
{
	int i,j,x,y,v;
	cin>>m>>n;//可承受总重量与物品数 
	for (i=1;i<=n;i++)cin>>a[i]>>c[i];//依次读入重量与价值 
	for (i=1;i<=n;i++)//将每件物品依次循环 
	  for (v=m;v>=a[i];v--)
	  if (b[v-a[i]]+c[i]>b[v])//如果当前装好第i件物品剩下重量可承受价值>装前 
	    b[v]=b[v-a[i]]+c[i];//更新其重量下可装价值。 
	cout<<b[m];//输出最大总价值 
	return 0;
}
//B数组下标表示的是重量,B数组本身保存的是当前重量下可装的最大价值。 

上面是代码,这里就不详细说了。
代码为了优化空间,将“V”这一下标转化为了物品的重量,降低了一维吃我降维打击!
思想代码中已附

完全背包

完全背包即是无限物品的背包,这里要用到一些贪心壮哉我大贪心

其实完全背包写法实现只不过是将物品重量正向枚举,而不是反向枚举。这样就不会像01包一样令物品不会重复放置了(大的放完小的就放不下了,所以不会重复)
总的思想类似于贪心,总之就是要让好的物品越多越好,直到不能再放。
若要优化的话,可以去尝试省略掉一些重量又大,价值又低的物品。也就是w[i]>w[j] c[i]<c[j]。第i件可直接删掉。
下面是代码

#include<bits/stdc++.h>
using namespace std;
int a[20001],c[20001],b[30001],m,n;
int main()
{
	int i,j,x,y,v;
	cin>>m>>n;//可承受总重量与物品数 
	for (i=1;i<=n;i++)cin>>a[i]>>c[i];//依次读入重量与价值 
	for (i=1;i<=n;i++)//将每件物品依次循环 
	  for (v=a[i];v<=m;v++)//就这行有变化
	  if (b[v-a[i]]+c[i]>b[v])//如果当前装好第i件物品剩下重量可承受价值>装前 
	    b[v]=b[v-a[i]]+c[i];//更新其重量下可装价值。 
	cout<<b[m];//输出最大总价值 
	return 0;
}
//B数组下标表示的是重量,B数组本身保存的是当前重量下可装的最大价值。 

就这么简单。

其他背包都是尽力化简为01包,这里只轻轻点一下。

多重背包

即物品数量有限制的完全包,思想类似完全,不过还要加数量这一限制条件,也是疯狂放好的物品,直到数量用完或是放不下

混合三种背包

综合01包与完全包,写起来很恶心有意思

#include<bits/stdc++.h>
using namespace std;
int m,n;
int w[31],c[31],p[31];
int f[201];
bool cmp(int x,int y)
{
	return x>y;
}
int main()
{
	int i,j,x,y,k;
    cin>>n>>m;
    for (i=1;i<=n;i++)
     cin>>w[i]>>c[i]>>p[i];
    for (i=1;i<=n;i++)
    {
    	if (p[i]==-1)
    	{
    		for (j=w[i];j<=m;j++)
    		 f[j]=max(f[j],f[j-w[i]]+c[i]);
		}
		else 
		{
			for (j=1;j<=p[i];j++)
			  for (k=m;k>=w[i];k--)
			    f[k]=max(f[k],f[k-w[i]]+c[i]);
		}
	}
	cout<<f[m];
	return 0;
}

二维费用的背包问题

多了个限制条件的01包,数组多一维即可。写起来也很恶心有意思

分组包

物品分组,组内只可选一样。
组内枚举,组外01包。还是写起来很恶心有意思

依赖包

初一蒟蒻没学过树,并不会写

背包方案总数

过个时间再补充。

猜你喜欢

转载自blog.csdn.net/qq_39441542/article/details/84674997