POJ 3624/USACO 2007 DEC: 01揹包


——01揹包模板題
原題傳送門1
原題傳送門2

Description

Bessie has gone to the mall’s jewelry store and spies a charm bracelet.
Of course, she’d like to fill it with the best charms possible from the N available charms.
Each charm i in the supplied list has a weight Wi, a ‘desirability’ factor Di ,
and can be used at most once.
Bessie can only support a charm bracelet whose weight is no more than M.
Given that weight limit as a constraint and a list of the charms
with their weights and desirability rating,
deduce the maximum possible sum of ratings.

Data

Input
Input will consist of a series of real numbers no greater than $300.00 each on a separate line. Each
amount will be valid, that is will be a multiple of 5c. The file will be terminated by a line containing
zero (0.00).
Output
Output will consist of a line for each of the amounts in the input, each line consisting of the amount
of money (with two decimal places and right justified in a field of width 6), followed by the number of
ways in which that amount may be made up, right justified in a field of width 17.

	Sample Input
	0.20
	2.00
	0.00
	Sample Output
	0.20 			4	 //近似
	2.00 			293  //近似

1≤N≤3402 1≤M≤12,880 1≤Wi≤400 1≤Di≤100

思路:

好像是 不需要寫 的01揹包

經典DP揹包: 0/1(01)揹包

題目描述如下:

給定一個限重W的揹包,有一系列物品Ai,各有一重量Wi和價值Vi,要求這些物品要麼放要麼不放,問不超過限重的情況下,拿到的最大價值是多少.

主要因素

用i表示選到第i個物品(階段)
用j表示揹包的重量(狀態)

這樣我們的DP就是 dpi j (dp[N][M])了

DP方程

於是對於每個物品Ai ,有選/不選 兩種選擇

對應地,dp[i][j]=max(dp[i-1]j,dp[i-1][j-W[i]]+Vi)
但是,揹包不能爲負!
於是,這個狀態轉移方程就變爲:

If j>=W[i] dp[i][j]=max(dp[i-1][j],dp[i-1][j-W[i]]+V[i]))
Else dp[i][j]=dp[i-1][j]

具體問題還需讀者自行實現

時空複雜度

時間複雜度

時間複雜度O(NM) 約爲 3*107
可以接受不再討論

空間複雜度

空間複雜度O(NM) 約爲 3*107
這個複雜度是無法接受的…
於是,便有

有條件要上,沒有條件創造條件也要上。

考慮上面的轉移方程,可以發現dp[i-2]的所有狀態都是不需要的.
於是,我們拋棄它們覆蓋它們.
現在,我們的DP數組就變成dp[2][M] 了 ?
但真的不能再優化了嗎?
仔細觀察轉移方程,發現j狀態後面的狀態,其實不能影響j
換句話說,j狀態只依賴於前面的狀態!
所以,我們連i這一維都可以省略,只需在j循環時倒序掃描即可.

Code

// 沒有降維(MLE爆空間)
int dp[N][M];
int main()
{
	for (int i=1;i<=n;i++)
		for (int j=0;j<=m;j++)
			if (j>=w[i]) dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
			else dp[i][j]=dp[i-1][j];
	printf("%d\n",dp[n][m]);
}
// 降空間
int dp[2][M];
int main()
{
	for (int i=1;i<=n;i++)
		for (int j=0;j<=m;j++)
			if (j>=w[i]) dp[i&1][j]=max(dp[(i-1)&1][j],dp[(i-1)&1][j-w[i]]+v[i]);
			else dp[i&1][j]=dp[(i-1)&1][j];
	printf("%d\n",dp[n&1][m]);
}
//降維
int dp[M];
int main()
{
	for (int i=1;i<=n;i++)
		for (int j=m;j>=w[i];j--)
			dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
	printf("%d\n",dp[m]);
}

感謝奆老關注 qwq ?

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