其他分享
首页 > 其他分享> > 背包九讲

背包九讲

作者:互联网

视频链接:背包九讲专题_哔哩哔哩_bilibili

 

一,01 背包问题

题目链接:2. 01背包问题 - AcWing题库

题解:

二维代码:

  f [ i ][ j ] 表示只考虑到前 i 个物品,且总体积恰好是 j 的情况下,总价值最大是多少

  递推式:

    情况①:不选第 i 个物品,f [ i ][ j ] = f [ i - 1 ][ j ] 

    情况②:选第 i 个物品,f [ i ][ j ] = f [ i - 1 ][ j - v[i] ] + w[ i ]

    f [ i ][ j ] = max(①,②)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define N 1010
int n, m;    // 物品数,背包体积
int f[N][N];
int v[N], w[N]; // 物品体积,物品价值
int max(int a, int b)
{
	return a > b ? a : b;
}
int main(void)
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%d%d", &v[i], &w[i]);

	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			f[i][j] = f[i - 1][j]; // 默认不选
			if (j >= v[i]) // 如果可以选,即背包体积大于物品体积
				f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
		}
	}

	printf("%d\n", f[n][m]);

	system("pause");
	return 0;
}

解析:

			f[i][j] = f[i - 1][j]; // 默认不选
			if (j >= v[i]) // 如果背包体积大于物品体积
				f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);

上面这段代码就是从第 i-1 个物品的状态,推导第 i 个物品的状态的递推式。相较于上文 “选于不选” 的判断条件,这里省略了 “不选“ 的判断条件,并在可以选择的时候,比较选与不选各自的价值。也可以理解为:不能选的话,只能不选;可以选的话,就要看选与不选哪个价值大咯。

 

二维压缩为一维:01 背包的空间优化

  f [ j ] 表示 如果当前考虑的是 i 个物品,那么在总体积恰好是 j 的情况下,只考虑到前 i - 1 个物品的总价值最大是多少

  递推式:从第 i-1 个物品的状态,推导出第 i 个物品的状态

    情况①:不选第 i 个物品,f [ j ] = f [ j ] ,(注意,虽然这里等式左右一样,但意义不一样,等式左边代表的是只考虑到前 i  个物品,而等式右边代表的是只考虑到前 i - 1 个物品。下文会将这种从 只考虑到前 i - 1 个物品 到 只考虑到前 i  个物品 的变化叫刷新。这也是为什么第二层循环要从后往前循环的原因 )

    情况②:选第 i 个物品,f [ j ] = f[ j - v[i] ] + w[ i ],(注意,f [ j ] 代表的是只考虑到前 i  个物品, f[ j - v[i] ] 代表的是只考虑到前 i - 1 个物品。下文会将这种从 只考虑到前 i - 1 个物品 到 只考虑到前 i  个物品 的变化叫刷新。这也是为什么第二层循环要从后往前循环的原因 )

    f [ i ][ j ] = max(①,②)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define N 1010
int n, m;    // 物品数,背包体积
int f[N];
int v[N], w[N]; // 物品体积,物品价值
int max(int a, int b)
{
	return a > b ? a : b;
}
int main(void)
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%d%d", &v[i], &w[i]);

	for (int i = 1; i <= n; i++)
		for (int j = m; j >= v[i]; j--)
			f[j] = max(f[j], f[j - v[i]] + w[i]);

	printf("%d\n", f[m]);

	system("pause");
	return 0;
}

解析:

			f[j] = max(f[j], f[j - v[i]] + w[i]);

上面这段代码就是从第 i-1 个物品的状态,推导第 i 个物品的状态的递推式。因为不选是 f[ j ] = f[ j ],没有变化,所以虽然这里没有表示出不选的代码,但实际上还是有这个含义的。再来说一下不选,f[ j - v[ i] ] + w[ i ],问题就出在这个 f[ j - v[ i] ] 身上,因为如果我们 j 是正常的从小到大递增的话,那么 f[ j ] 肯定 还没经过刷新,但 f[ j - v[ i] ] 就一定经过刷新,所以此时 f[ j - v[ i] ] 代表的是 “只考虑到前 i  个物品”,而不是我们需要的 “只考虑到前 i - 1 个物品”。那么如何在一次 j 循环中,保证用到的 f[ j - v[ i] ] 都没有刷新过呢?只能是从后往前循环了。 ♪(^∀^●)

所以,内层循环从二维压缩到一维就是:

		for (int j = m; j >= 0; j--)
		{
			f[j] = f[j];  // 不选
			if(j >= v[i]) // 可以选,比较选与不选的价值
				f[j] = max(f[j], f[j - v[i]] + w[i]);
		}

进一步优化就是:

		for (int j = m; j >= v[i]; j--)
			f[j] = max(f[j], f[j - v[i]] + w[i]);

  

 

 

 

 

 

二,完全背包问题

三,多重背包问题

四,混合背包问题

五,二维费用的背包问题

六,分组背包问题

七,背包问题求方案数

八,求背包问题的方案

九,有依赖的背包问题

 

========== ========= ======== ====== ====== ===== ==== === == =

标签:背包,九讲,int,max,不选,体积,物品
来源: https://www.cnblogs.com/asdfknjhu/p/15041776.html