背包板子

为了能成功记住各种各样千奇百怪的背包,我照着我的小橙书把上面的东西都敲上去了嘤嘤嘤

一、01背包

一个旅行者有一个最多能装M公斤的背包,现在有n件物品,它们的重量分别是W1,W2......Wn;它们的价格为C1,C2......Cn,求旅行者能获得的最大总价值.

#include<bits\stdc++.h>
using namespace std;
int w[1003],c[1003],f[1003];
int n,m;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i++)
    {
        scanf("%d%d",&w[i],&c[i]);
        for(int j = m;j >= w[i];j--)
        {
            f[j] = max(f[j],f[j - w[i]] + c[i];
        }
    } 
    printf("%d",f[m]);
    return 0;
}

二、完全背包

有N种物品和一个容量为V的背包,每种物品都有无限件可以用。第i种物品的的费用是w[ i ],价值是c[ i ]。求解将哪些物品装入背包的费用总和不超过背包容量,且价值总和最大。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int m,n;
int w[1003],c[1003],f[1003]; 
int main()
{
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;i++)
	{
		scanf("%d%d",&w[i],&c[i]);
		for(int j = w[i];j <= m;j++)//01背包是倒序,完全背包是顺序 
		{
			f[j] = max(f[j],f[j - w[i]] + c[i]);
		} 
	} 
	printf("%d",f[m]);
	return 0;	
} 

三、多重背包问题

有N种物品和一个容量为V的背包。第i种物品最多有n[ i ],每件费用是w[ i ],价值是c[ i ]。求解将哪些物品放入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int m,n;
int w[1003],c[1003],s[1003],f[1003]; 
int main()
{
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;i++)
	{
		scanf("%d%d%d",&w[i],&c[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 * w[i] < 0)break;
				f[j] = max(f[j],f[j - k * w[i]] + k * c[i]);
			}
		}
	}
	printf("%d",f[m]);
	return 0;	
} 

四、多种背包混合问题

一个旅行者有一个最多能装V公斤的背包,现在有n件物品,已知它们的价值和所占体积。有的物品可以一次取一件,有的物品可以取无限次,有的物品可以取得个数有上限。求最大价值。

//无法理解出题人为什么非要把这三个背包放在一起,有毒吧。。。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int m,n;
int w[1003],c[1003],s[1003],f[1003]; 
int main()
{
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;i++)
	{
		scanf("%d%d%d",&w[i],&c[i],&s[i]);
	} 
	for(int i = 1;i <= n;i++)
	{
		if(s[i] == 0)
		{
			for(int j = w[i];j <= m;j++)
			{
				f[j] = max(f[j],f[j - w[i]] + c[i]);
			}
		}
		else{
			for(int j = 1;j <= s[i];j++)
			{
				for(int k = m;k >= w[i];k--)
					f[k] = max(f[k],f[k - w[i]] + c[i]);
			}
		}
	}
	printf("%d",f[m]);
	return 0;	
} 

五、二维费用的背包问题

小橙书上关于这个讲了一大堆,大意就是限制条件有之前的一个变成了两个,就是由之前得背包重量,变成了现在的氢气和氧气的含量。

例题:潜水员

潜水员有一个带2种气体的气缸:一个为氧气,一个为氮气。他有一定数量的气缸。每个气缸都有重量和气体容量。潜水员为了完成他的工作需要特定数量的氧和氢。他完成工作所需气缸的总重的最低限度是多少

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
//啊啊啊de了一万年bug终于过了
int u,v,k;
int f[101][101];
int a[1001],b[1001],c[1001];
int main()
{
	memset(f,10001,sizeof(f));//要把数组初始化为一个很大的数
	f[0][0] = 0;
	scanf("%d%d%d",&v,&u,&k);
	for(int i = 1;i <= k;i++)
	{
		scanf("%d%d%d",&a[i],&b[i],&c[i]);
	}
	for(int i = 1;i <= k;i++)
	{
		for(int j = v;j >= 0;j--)
		{
			for(int x = u;x >= 0;x--)
			{
				int t1 = j + a[i],t2 = x + b[i];//设一个变量方便计算
				if(t1 > v)t1 = v;//如果超出需求量就用需求量代替				                if(t2 > u)t2 = u;//这样就可以用f[v][u]来表示最优解了
				f[t1][t2] = min(f[t1][t2],f[j][x] + c[i]);
			}
		}
	}
	printf("%d",f[v][u]);
	return 0;
} 
/*
5 60
5
3 36 120
10 25 129
5 50 250
1 45 130
4 20 119
*/

正解是最后输出249

六、分组的背包问题

有完没完,难道我真的要把自己的大好人生都用来学习背包吗!!!

问题:

有N件物品和一个容量为V的背包。第i件物品的费用是w[ i ],价值是c[ i ]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品放入背包中可使这鞋物品的费用总和不超过背包容量,且价值总和最大

对每一组物品,可以选择其中的一件或者一件都不选

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
//这段代码简直有毒,我照着小橙书一个字一个字地敲得,结果竟然过不了样例
int v,n,t;
int w[33],c[33];
int a[13][33],dp[203];
int main()
{
	scanf("%d%d%d",&v,&n,&t);
	for(int i = 1;i <= n;i++)
	{
		int p;
		scanf("%d%d%d",&w[i],&c[i],&p);
		a[p][++a[p][0]] = i;//记录下来它属于哪个组 
	}
	for(int x = 1;x <= t;x++)
	{
		for(int j = v;j >= 0;j--)
		{
			for(int i = 1;i <= a[x][0];i++)
			{
				if(j >= w[a[x][i]])
				{
					int q = a[x][i];
					dp[j] = max(dp[j - w[q]] + c[q],dp[j]);
				}
			}
		}
	}
	printf("%d",dp[v]);
	return 0;
}
/*
10 6 3
2 1 1
3 3 1
4 8 2
6 9 2
2 8 3
3 9 3
*/

//输出20

七、有依赖的背包问题

这种背包问题的物品间存在某种依赖关系。若i依附于j,表示若选物品i,则必须选物品j。对每个主见i的附件集合先进行一次01背包,将主件转化为一个物品组,然后就可以按照分组背包来进行计算了。
然后有一道金明的预算方案我等会去写一下

八、背包问题方案总数

对于这类问题,一般只需要将状态转移方程中的max改成sum即可

详情见https://blog.csdn.net/qq_42914224/article/details/82563792

猜你喜欢

转载自blog.csdn.net/qq_42914224/article/details/81806068
今日推荐