poj3624 Charm Bracelet
http://poj.org/problem?id=3624
題目大意:貝茜去了商場的珠寶店,發現了一個迷人的手鐲。當然,她想裝最好的魅力(N(1≤N≤3402)可用的魅力)。每個魅力提供的列表中都有一個重量Wi(1≤Wi≤400),一個“願望”因素Di(1≤Di≤100),最多可以使用一次。貝茜只能支持一個重量不超過M的魅力手鐲。
*第1行:兩個空格分隔的整數:N和M。
*第2 …N+1行:第i+1行描述了具有兩個空間分離整數的魅力i: Wi和Di。考慮到重量限制作為一種約束,並列舉了它們的重量和可取性的魅力,推斷出魅力最大可能的取值。
也就是說,這個問題是01背包問題,設x[ i ]為1表示第i個珠寶放入手鏈,為0則不放入,那麽原問題就變成了求 約束條件是 , 我們可以采用動態規劃,回溯法,分支限界法等來解決該問題。這裏采用動態規劃求解。
算法思想:動態規劃
a) 把背包問題抽象化(X1,X2,…,Xn,其中 Xi 取0或1,表示第 i 個物品選或不選),Di表示第 i 個物品的價值,Wi表示第 i 個物品的體積(重量);
b) 建立模型,即求max(D1X1+D2X2+…+DnXn);
c) 約束條件,W1X1+W2X2+…+WnXn<=M;
d) 定義V(i,j):當前背包容量 j,前 i 個物品最佳組合對應的價值;
e) 最優性原理是動態規劃的基礎,最優性原理是指“多階段決策過程的最優決策序列具有這樣的性質:不論初始狀態和初始決策如何,對於前面決策所造成的某一狀態而言,其後各階段的決策序列必須構成最優策略”。判斷該問題是否滿足最優性原理,采用反證法證明:
假設(X1,X2,…,Xn)是01背包問題的最優解,則有(X2,X3,…,Xn)是其子問題的最優解,
假設(Y2,Y3,…,Yn)是上述問題的子問題最優解,則理應有(D2Y2+D3Y3+…+DnYn)+D1X1 > (D2X2+D3X3+…+DnXn)+D1X1;
而(D2X2+D3X3+…+DnXn)+D1X1=(D1X1+D2X2+…+DnXn),則有(D2Y2+D3Y3+…+DnYn)+D1X1 > (D1X1+D2X2+…+DnXn);
該式子說明(X1,Y2,Y3,…,Yn)才是該01背包問題的最優解,這與最開始的假設(X1,X2,…,Xn)是01背包問題的最優解相矛盾,故01背包問題滿足最優性原理;
f) 尋找遞推關系式,面對當前商品有兩種可能性:
第一,背包的容量比該商品體積小,裝不下,此時的價值與前i-1個的價值是一樣的,即V(i,j)=V(i-1,j);
第二,還有足夠的容量可以裝該商品,但裝了也不一定達到當前最優價值,所以在裝與不裝之間選擇最優的一個,即V(i,j)=max{ V(i-1,j),V(i-1,j-W(i))+D(i) }
其中V(i-1,j)表示不裝,V(i-1,j-W(i))+D(i) 表示裝了第i個商品,背包容量減少W(i)但價值增加了v(i);
由此可以得出遞推關系式:
1) j<W(i) V(i,j)=V(i-1,j)
2) j>=W(i) V(i,j)=max{ V(i-1,j),V(i-1,j-W(i))+D(i) }
到此便能解決,但是你會發現,這樣提交空間會溢出,不滿足,所以我們要對其進行空間優化。
g) 空間優化,每一次V(i)(j)改變的值只與V(i-1)(x) {x:1...j}有關,V(i-1)(x)是前一次i循環保存下來的值;
因此,可以將V縮減成一維數組,從而達到優化空間的目的,狀態轉移方程轉換為 result(j)= max{result(j), result(j-W(i))+D(i)};
並且,狀態轉移方程,每一次推導V(i)(j)是通過V(i-1)(j-w(i))來推導的,所以一維數組中j的掃描順序應該從大到小(M到0),否者前一次循環保存下來的值將會被修改,從而造成錯誤。
h) 然而不足的是,雖然優化了動態規劃的空間,但是該方法不能找到最優解的解組成,因為動態規劃尋找解組成一定得在確定了最優解的前提下再往回找解的構成,而優化後的動態規劃只用了一維數組,之前的數據已經被覆蓋掉,所以沒辦法尋找,所以兩種方法各有其優點。但是這樣提交可以通過。
1 #include <iostream> 2 using namespace std; 3 #define MAXN 3403 4 #define MAXM 12881 5 int w[MAXN]; 6 int d[MAXN]; 7 int result[MAXM]; 8 int main() 9 { 10 int N; 11 int M; 12 cin >> N >> M; 13 14 for (int i = 1; i <= N; i++) 15 { 16 cin >> w[i] >> d[i]; 17 } 18 for (int tempN = 1; tempN <= N; ++tempN) //對第tempN個物品 19 { 20 for (int tempM = M; tempM >= w[tempN]; tempM--)//背包容量從大到小 21 { 22 if (result[tempM] <= result[tempM - w[tempN]] + d[tempN])//比較裝與不裝的價值 23 { 24 result[tempM] = result[tempM - w[tempN]] + d[tempN]; //二維變一維 25 } 26 } 27 } 28 cout << result[M] << endl; 29 30 return 0; 31 }
poj3624 Charm Bracelet