01揹包動態規劃空間優化

葡萄成熟時xycjc發表於2019-02-12

問題描述:

給定 n 種物品和一個容量為 w 的揹包,物品 i 的價值是 vai,其體積為 voi。

問:應該如何選擇裝入揹包的物品,使得裝入揹包中的物品的總價值最大?

 

解題思路:

狀態轉移方程為:

dp[i][j] = dp[i-1][j]                                                      j < vo[i]   (即此時的揹包容積小於第i個物品的體積)

dp[i][j] = max( dp[i-1][j] , dp[i-1][j-vo[i]] + va[i] )        j >= vo[i] (當揹包容積大於第 i 個物品的體積時,有兩種選擇,選較大的一個)

兩種選擇:

1、不裝這個物品 。則此時dp陣列的值還是第i-1個物品是的值,即dp[i-1][j]

2、裝下這個物品,此時是dp[i-1][j-vo[i]] + va[i],然後與不裝比較看哪種情況裝的物品的價值更大

 

程式碼:

#include<stdio.h>
#include<algorithm>
using namespace std;

int dp[105][105];
int va[105] , vo[105];//每件物品的價值va和體積vo

int main()
{
	int w , n ;//揹包的總容量,物品的件數
	scanf("%d %d",&n,&w);
	for(int i = 1 ; i <= n ; i++)
	{
		scanf("%d %d",&va[i],&vo[i]);
	}
	
	for(int i = 1 ; i <= n ; i++)
	{
		for(int j = 0 ; j <= w ; j++)
		{
			if( vo[i] > j)
			{
				dp[i][j] = dp[i-1][j];
			}
			else
			{
				dp[i][j] = max(dp[i-1][j] , dp[i-1][j-vo[i]] + va[i]);
			}
		}
	} 
	printf("%d\n",dp[n][w]);
	
	
	return 0;
	
 } 

 

空間優化程式碼:

只開闢一維dp陣列,每次更新是重最後向前迴圈,畢竟只需要最後一個結果,中間的過程可以不儲存,但一定確保從後向前迴圈

#include<stdio.h>
#include<algorithm>
using namespace std;


int va[105] , vo[105];//每個物品的價值和體積 
int dp[105];

int main()
{
	int n , w;//物品數量和揹包容積 
	scanf("%d %d",&n,&w);
	for(int i = 1 ; i <= n ; i++)
	{
		scanf("%d %d",&va[i] , &vo[i]);
	}
	for(int i = 1 ; i <= n ; i++)
	{
		for(int j = w ; j >= vo[i] ; j--)//要倒著進行,確保在沒有被更新的狀態下使用 
		{
			dp[j] = max(dp[j - vo[i]] + va[i] , dp[j]);
		}
	}
	printf("%d",dp[w]);
	
	return 0;
} 

 

相關文章