导航

动态规划 -- 01背包问题

Posted on 2022-05-31 14:44  wuqiu  阅读(16)  评论(0编辑  收藏  举报

朴素解法 -- 二维数组

初始化
因为f[N][N]定义在堆中,会自动初始化为零。此时算出背包容量为M的时候的最大值,未必是全部装满的最大值,背包中可能会有剩余。若想算出正好装满的,需要对初始化做改动:将f[N][0]复制为零,其余的赋值为负无穷,这样在状态转移的时候可以保证所有可以作为更改的项全部都由f[N][0]转移过来,其他的都太小在取max的时候选不到。

状态转移方程
f[i][j] 的状态表示在有i个物体、j个背包体积的情况下所选最优解。该状态由f[i-1]推出。从f[i-1]到f[i]有两种选择情景,分别为选择f[i]与不选择f[i]。
选择f[i] : f[i][j] = f[i - 1][j - wei[i]] + val[i] ;
不选择f[i] : f[i][j] = f[i - 1][j];

#include <bits/stdc++.h>
using namespace std;

const int N = 1010;

int f[N][N];
int n, m;
int wei[N];
int val[N];

int main ()
{
	cin >> n >> m;
	for(int i = 1; i<= n ; i++)	cin >> wei[i] >> val[i];
	for(int i = 1; i<= n ; i++)
	{
		for(int j = 0; j<=m ; j++)
		{
			f[i][j] = f[i-1][j];
			if( j >= wei[i])	f[i][j] = max(f[i][j] , f[i-1][j - wei[i]] + val[i]);
		}
	}
	cout << f[n][m];
	return 0;
}

优化 : 二维数组变为一维数组

针对选择f[i]的情况 : f[i][j] = f[i - 1][j - wei[i]] + val[i] ; 变为一维数组之后 : f[j] = f[j - wei[i]] + val[i]; 此时要保证使用的f[j - wei[i]]是在f[i-1]中算出的数据,但是如果保持原循环 j from 0 to m 的顺序,则所用f[j - wei[i]] 则是f[i]中算出的数据,所以循环改为 j from m to wei[i] (如果剩余重量不足以装下 i 物体的话,则不需要运算)

#include <bits/stdc++.h>
using namespace std;

const int N = 1010;

int n, m;
int f[N];
int wei[N];
int val[N];

int main ()
{
	cin >> n >> m;
	for(int i = 1; i<= n ; i++)	cin >> wei[i] >> val[i];
	for(int i = 1 ; i <= n; i++)
	{
		for(int j = m ; j >= wei[i] ; j-- )
		{
			f[j] = max(f[j] , f[j - wei[i]] + val [i]);
		}
	}
	cout << f[m];
	return 0;
}