01揹包問題HDU2602

2022-05-17 17:24:02 字數 2760 閱讀 3472

典型的01揹包問題,用動態規劃來解即可。

用子問題定義狀態:即f[i][v]表示前i件物品恰放入乙個容量為v的揹包可以獲得的最大價值。

則其狀態轉移方程便是: f[i][v]=max 這個方程非常重要

,基本上所有跟揹包相關的問題的方程都是由它衍生出來的。所以有必要將它詳細解釋一下:「將前i件物品放入容量為v的揹包中」這個子問題,若只考慮第i件物品的策略

(放或不放),那麼就可以轉化為乙個只

牽扯前i-1件物品的問題。如果不放第i件物品,那麼問題就轉化為「前i-1件物品放入容量為v的揹包中」,價值為f[i-1][v];

如果放第i件物品,那麼問題就轉化為「前i-1件物品放入剩下的容量為v-c[i]的背

包中」,此時能獲得的最大價值就是f[i-1][v-c[i]]再加上通過放入第i件物品獲得的價值w[i]。

開始時用的二維陣列做,i從1開始到n,j從0到n,完成整個矩陣,這裡知道了,其實之前的很多無用功都是為了在之後的呼叫時能夠縮短時間,這也是遞迴轉向遞推,中間值進行

保留的思想

1 #include2 #include

3int dp[1001][1001];4

int max(int a,intb)5

8int

main()

927 printf("

%d\n

", dp[n][v]);28}

29return0;

30 }

view code

在空間上還能再優化

優化空間複雜度 以上方法的時間和空間複雜度均為o(n*v),其中時間複雜度基本已經不能再優化了,但空間複雜度卻可以優化到o(v)。 先考慮上面講的基本思路如何實現,肯定是有乙個主迴圈i=1..n,

每次算出來二維陣列f[i][0..v]的所有值。那麼,如果只用乙個陣列f[0..v],能不能保證第i次迴圈結束後f[v]中表示的就是我們定義的狀態f[i][v]呢?f[i][v]是由f[i-1][v]和

f[i-1][v-c[i]]兩個子問題遞推而來,能否保證在推f[i][v]時(也即在第i次主迴圈中推f[v]時)能夠得到f[i-1][v]和f[i-1][v-c[i]]的值呢?事實上,這要求在每次主迴圈中我們以v=v..0

的順序推f[v],這樣才能保證推f[v]時f[v-c[i]]儲存的是狀態f[i-1][v-c[i]]的值。偽**如下: for i=1..n for v=v..c[i] f[v]=max; 其中的

f[v]=max一句恰就相當於我們的轉移方程f[i][v]=max,因為現在的f[v-c[i]]就相當於原來的f[i-1][v-c[i]]。如果將v的迴圈順序從上面

的逆序改成順序的話,那麼則成了f[i][v]由f[i][v-c[i]]推知,與本題意不符,但它卻是另乙個重要的揹包問題p02最簡捷的解決方案,故學習只用一維陣列解01揹包問題是十分必要的。 事實上,使

用一維陣列解01揹包的程式在後面會被多次用到,所以這裡抽象出乙個處理一件01揹包中的物品過程,以後的**中直接呼叫不加說明。 過程zeroonepack,表示處理一件01揹包中的物品,兩個引數

cost、weight分別表明這件物品的費用和價值。 procedure zeroonepack(cost,weight) for v=v..cost f[v]=max 注意這個過程裡的處理與

前面給出的偽**有所不同。前面的示例程式寫成v=v..0是為了在程式中體現每個狀態都按照方程求解了,避免不必要的思維複雜度。而這裡既然已經抽象成看作黑箱的過程了,就可以加入優化。費用為

cost的物品不會影響狀態f[0..cost-1],這是顯然的。 有了這個過程以後,01揹包問題的偽**就可以這樣寫: for i=1..n zeroonepack(c[i],w[i]); 初始化的細節問題 我們看到的

求最優解的揹包問題題目中,事實上有兩種不太相同的問法。有的題目要求「恰好裝滿揹包」時的最優解,有的題目則並沒有要求必須把揹包裝滿。一種區別這兩種問法的實現方法是在初始化的時候有所不同。

如果是第一種問法,要求恰好裝滿揹包,那麼在初始化時除了f[0]為0其它f[1..v]均設為-∞,這樣就可以保證最終得到的f[n]是一種恰好裝滿揹包的最優解。 如果並沒有要求必須把揹包裝滿,而是只

希望**盡量大,初始化時應該將f[0..v]全部設為0。 為什麼呢?可以這樣理解:初始化的f陣列事實上就是在沒有任何物品可以放入揹包時的合法狀態。如果要求揹包恰好裝滿,那麼此時只有容量為0的

揹包可能被價值為0的nothing「恰好裝滿」,其它容量的揹包均沒有合法的解,屬於未定義的狀態,它們的值就都應該是-∞了。如果揹包並非必須被裝滿,那麼任何容量的揹包都有乙個合法解「什麼都不裝」,

這個解的價值為0,所以初始時狀態的值也就全部為0了。 這個小技巧完全可以推廣到其它型別的揹包問題,後面也就不再對進行狀態轉移之前的初始化進行講解。 小結 01揹包問題是最基本的揹包問題,它

包含了揹包問題中設計狀態、方程的最基本思想,另外,別的型別的揹包問題往往也可以轉換成01揹包問題求解。故一定要仔細體會上面基本思路的得出方法,狀態轉移方程的意義,以及最後怎樣優化的空間

複雜度。

1 #include2 #include

3int dp[1001];4

int max(int a,intb)5

8int

main()

925 printf("

%d\n

", dp[v]);26}

27return0;

28 }

view code

HDU 2602 撿骨頭 入門DP之01揹包

第二道dp題,覺得01揹包還是很套路的 直接分析了 t組資料 然後輸入兩個數字,第乙個代表n個數,第二個代表包袱總容積,後輸入體積和價值 2 通過比較體積來轉化成價值就好 然後就是熟悉的狀態方程,詳情請看第乙個題 ac include include include using namespace ...

hdu1171 hdu2602 簡單01揹包

hdu1171 將總額的一半作為揹包容量,狀態方程s j max s j s j v i v i include include includeusing namespace std int v 5000 int s 250000 int main void int max 1 for i 1 i ...

揹包問題 01揹包問題

n個物品,總體積是v,每個物品的體積的vi,每個物品的最大價值是wi,在不超過v的體積下求最大價值 eg揹包容積為 5 物品數量為 4 物品的體積分別為 物品的價值分別為 思路定義乙個二位陣列int f new int n 1 v 1 f i j 就表示在1 i個物品中選取體積小於v的情況的最大價值...