1. 程式人生 > >TOJ 3596. Watch The Movie【基礎的二維費用揹包問題】

TOJ 3596. Watch The Movie【基礎的二維費用揹包問題】

           昨天訓練賽有一道二維費用揹包的題,結果我守著揹包九講在手邊就是沒做出來。事後發現其實解法揹包九講都已經講到了,只不過自己看的不仔細罷了。以後看解題報告也好,論文也好,一定要深入思考一下,真正將這個問題搞懂並且做到可以拓展,那才是真正的學懂了。

           先說一下二維費用揹包吧,我們都知道揹包問題,有01揹包,完全揹包,多重揹包。。。其中01揹包是指有N件物品,每種物品只有一件,可以選擇拿或者不拿,每個物品有一個重量和一個價值,找出不超過揹包容量可獲得的最大價值。完全揹包是在01揹包的基礎上是指每種物品有無數件可以拿,而多重揹包是指第i件物品有num [i]件可以拿。這3種揹包問題的解法類似,其中01揹包的轉移方程核心是“拿或者不拿”,所以有轉移方程: 

                         for(i = 1;i <= N; i++)                //N是指有N件物品

                               for(j = M;j >= cost[i]; j++)   // M是指揹包容量為M

                                      dp[j] = max(dp[j] , dp[j-cost[i]] + value[i] );  //拿或者不拿

           完全揹包的轉移方程只是在01的基礎上將第二重迴圈改為順序,即;

                         for(i = 1;i <= N; i++)                //N是指有N件物品

                               for(j = cost[i];j  <= M; j++)   // M是指揹包容量為M

                                      dp[j] = max(dp[j] , dp[j-cost[i]] + value[i] );  //拿或者不拿

           而多重揹包問題需要我們將每種物品的個數按照二進位制的思想拆分一下,對拆出來的每一種物品進行01揹包的操作(由於每種物品按照二進位制進行拆分,所以我們可以證明對每一種物品進行01揹包的操作可以保證可以得到任何一種個數的組合,即我們可以保證得到最優解)在拆分物品的過程中,如果某件物品的數量*cost 大於揹包容量,那麼可以理解為一個完全揹包,否則進行拆分,程式碼如下:

          上面這些都是一維費用的揹包,即每種商品只有一種費用,就是重量或者其他,二維費用的揹包是指,對於每一件物品,有兩個費用,選擇這個物品必須付出兩種代價,對於每種代價都有一個最大值,問怎麼選擇物品可以獲得最大的價值。

           演算法:費用加了一維,只需要狀態加一維即可。設dp[i][j] 表示付出兩種代價分別為i和j時可以得到的最大價值,那麼狀態轉移方程是:

          dp[i][j] = max(dp[i][j] , dp[i-a[k]][j-b[k]] + value[k]);

           這個方程和01揹包或者其他揹包類似,省了一維第幾個物品的狀態。在二維揹包問題下,如果每種物品只有一件,我們就按照01揹包的思路逆序迴圈,如果是完全揹包,則順序迴圈,如果是多重揹包,就按照拆分的思路寫,和前邊都差不多。

           物品個數的限制(摘自《揹包九講》)

           有時,“二維費用”的條件是以這樣一種隱含的方式給出的:最多隻能取M件物品。這事實上相當於每件物品多了一種“件數”的費用,每個物品的件數費用均為 1,可以付出的最大件數費用為M。換句話說,設f[v][m]表示付出費用v、最多選m件時可得到的最大價值,則根據物品的型別(01、完全、多重)用不 同的方法迴圈更新,最後在f[0..V][0..M]範圍內尋找答案。

           最後說一下很重要的初始化問題,如果沒有要求恰好裝滿,那麼初始化為0即可。如果要求恰好裝滿,我們在初始化時應該將個數為0時的數初始化為0,其餘初始化為負無窮。因為只有揹包容量為0的時候什麼都不取才合法。這種初始化的思想對於一切揹包問題都適用。

            說一下TOJ3596,題意很簡單,有N張光碟,每張光碟有一個價錢,現在要從N張光碟中買M張,預算為L,每張光碟有一個快樂值,要求在不超過預算並且恰好買M張,使得快樂值最大。

             分析:典型的二維費用揹包問題,另外一種隱含的費用為個數,每個物品的個數費用為1。要求恰好買M張表示要求恰好裝滿,所以初始化不是0,而是-INF。剩下的就是上面講到的狀態轉移方程了。