1. 程式人生 > 其它 >動態規劃 -- 01揹包問題

動態規劃 -- 01揹包問題

樸素解法 -- 二維陣列

初始化
因為f[N][N]定義在堆中,會自動初始化為零。此時算出揹包容量為M的時候的最大值,未必是全部裝滿的最大值,揹包中可能會有剩餘。若想算出正好裝滿的,需要對初始化做改動:將f[N][0]複製為零,其餘的賦值為負無窮,這樣在狀態轉移的時候可以保證所有可以作為更改的項全部都由f[N][0]轉移過來。

狀態轉移方程
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;
}