揹包問題詳細分析

首先是01揹包(1):奮鬥奮鬥

【題目描述】有n個重量和價值分別是wi,vi的物品。從這些物品中挑選出總重量不超過W的物品,求所有挑選方案中價值總和的最大值。


限制條件:(PS限制條件不同,動態方程也不同)

1 <= n <= 100;

1 <= wi,vi <= 100;

1 <= W <= 10000;//此處W較大,而wi,vi較小


輸入

n = 4

(w,v)={(2,3),(1,2)(3,4),(2,2)}

W = 5


輸出

7(選擇第0,1,3號物品)


【分析一】

dp[i+1][j]:從0到i這i+1個物品中選出總重量不超過j的物品時總價值的最大值

dp[0][j]=0;

            | dp[i][j]                            (j<w[i];

dp[i+1][j]= |

            | max(dp[i][j], dp[i][j-w[i]+v[i]})  (其他)。

void solve(){
	for(int i = 0; i < n; i++){
		for(int j = 0; j <= W; j++){
			if(j < w[i])
				dp[i+1][j] = dp[i][j];
			else
				dp[i+1][j] = max(dp[i][j], dp[i][j-w[i]+v[i]]); 
		}
	}
	printf("%d\n", dp[n][W]); 
}

【分析二】

void solve(){
	for(int i = 0; i < n; i++){
		for(int j = W; j >= w[i]; j--){//逆序 
			dp[j] = max(dp[j], dp[j- w[i]] + v[i]);
		}
	}
	printf("%d\n", dp[W]); 
}


01揹包(2):偷笑偷笑

還記得我們前面的條件嗎?在這裏,要把限制條件換一下

1 <= n <= 100

1 <= wi <= 10^7

1 <= vi <= 100

1 <= W <= 10^9


【分析】

dp[i+1][j]:=前i個物品中挑選出價值總和爲j時總質量的最小值(不存在時就是一個充分大的數值INF)

初始值

dp[0][0] = 0;

dp[0][j] = INF;

此外,前i個物品中挑選出機制總和爲j時,有

前i-1個物品中挑選價值總和爲j的部分

前i-1個物品中挑選價值總和爲j-v[i]的部分,然後再選中第i個物品

這兩種方法之一,所以就能得到

dp[i+1][j] = min(dp[i][j], dp[i][j-v[i] + w[i];

這一遞推式。最終的答案就在應以=於令dp[n][j] <= W的最大的j。


int dp[MAX_N+1][MAX_N * MAX_V + 1];//dp數組 
void solve(){
	fill(dp[0], dp[0] + MAX_N * MAX_V +1, INF);//此處需自己寫出代碼
	dp[0][0] = 0;
	for(int i = 0; i < n; i++){
		for(int j = 0; j < MAX_N * MAX_V; j++){
			if(j < v[i]){
				dp[i+1][j] = dp[i][j];
			}else{
				dp[i+1][j] = min(dp[i][j], dp[i][j-v[i]] + w[i]);
			}
		}
	} 
	int res = 0;
	for(int i = 0; i <= MAX_N * MAX_V; i++)
		if(dp[n][i] <= W) 
			res = i;
	printf("%d\n", res);
}


完全揹包:安靜安靜

【題目描述】有n個重量和價值分別是wi,vi的物品。從這些物品中挑選出總重量不超過W的物品,求所有挑選方案中價值總和的最大值。在這裏,每種物品可以挑選任意多件。


限制條件:

1<=n<=100

1<=wi,vi<=100

1<=W<=10000


輸入

n = 3

(w, v) = {(3,4), (4,5), (2,3)}

W = 7


輸出

10(0號物品選1個,2號物品選2個)


【分析一】

令dp[i+1][j]:=從前i種物品中挑選總重不超過j時總價值的最大值。

dp[0][j]=0;

             | max{dp[i-k*w[i]] + k*v[i]      | 0<=k;}

dp[i+1][j] = | 

             | max{dp[i][j-k*w[i]] + k*v[i]   | 0<=k;}

void solve(){
	for(int i = 0; i < n; i++){
		for(int j = 0; j <= W; j++){
			for(int k = 0; k*w[i] <= j; k++){
				dp[i+1][j] = max(dp[i+1][j], dp[i][j-k*w[i]] + k*v[i]);
			}
		}
	}
	printf("%d\n", dp[n][W]); 
}

【分析二】

void solve(){
	for(int i = 0; i < n; i++){
		for(int j = w[i]; j <= W; j++){//順序 
			dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
		}
	}
	printf("%d\n", dp[W]); 
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章