動態規劃之0-1揹包問題

問題描述:java

現 有n件物品和一個容量爲c的揹包。第i件物品的重量是重量爲w[i],價值是v[i]。已知對於一件物品必須選擇取(用1表示)或者不取(用0表示),且 每件物品只能被取一次(這就是「0-1」的含義)。求放置哪些物品進揹包,可以使這些物品的重量總和不超過揹包容量,且價值總和最大。app

求解思路:spa

假 設有5件物品,其重量分別是w={2,2,6,5,4},價值分別是v={6,3,5,4,6},揹包容量爲10。在數學問題中這是典型的線性規劃問題, 咱們能夠在線性約束範圍內求解目標表達式。可是怎麼用計算機語言實現呢?咱們能夠先這樣考慮,當揹包容量爲1時,如何放置物品才能使揹包中價值最大;一樣 當揹包容量爲2時,如何放置能使揹包中價值最大,以此類推,直到揹包容量爲10。此時咱們須要維護一張二維表m[i][j],其中橫座標i表示物品,縱坐 標表示揹包容量(1<=j<=10)。.net

                                                                                           0-1揹包問題的遞推二維表blog

                        


m[i] [j]表示當能夠放入前i件物品且揹包容量爲j時的最大價值。當只能放入第一件物品即i=0時:若揹包容量j<w[0],物品不可以被放入揹包;若 j>=w[0]時,物品能夠放入揹包,此時m[0][j]=v[0]。當能夠放入前2件物品即i=1時,咱們須要進行這樣的處理:若j< w[1]時,說明第2件物品不能被放入揹包內,此時揹包的最大價值爲揹包中只放入第一件物品的最大價值,即m[1][j]=m[0][j];若j& gt;=w[1]時,假設此時揹包容量j=8,第二件物品能夠被放入揹包內,那麼便會出現兩種狀況:遞歸

(1)將第二件物品放入揹包,那麼揹包中物品的最大價值是多少呢?由於第二件物品重量 爲w[1]=2,在將第二件物品放入揹包以前,揹包的容量應爲j-w[1]=8-2=6,此時揹包的最大價值是m[0][6],所以若將第二件物品放入背 包,其揹包的最大價值m[1][j]=m[0][j-w[1]]+v[1];ip

(2)不將第二件物品放入揹包,那麼此時揹包中物品的最大價值依然爲只放入第一件物品時揹包的最大價值,即m[1][j]=m[0][j];get

咱們選取(1)(2)中價值的較大者做爲i=1,j=8時揹包中的最大價值。數學

i=2,3,4時的分析同上,直到揹包的容量爲10,此時m[4][10]即爲揹包中物品的最大價值。flash

有了上面的分析,咱們很容易寫出下面的遞歸關係:

(1)i=0  當j<w[0]時,m[0][j]=0;當j>=w[0]時,m[0][j]=v[0]。

(2)i>0  當j<w[i],m[i][j]=m[i-1][j];當j>=w[i],m[i][j]=max{m[i-1][j-w[i]]+v[i],m[i-1][j]}。

獲得了知足約束條件的揹包中物品的最大價值後,須要知道是哪些物品被放入了揹包。觀察二維表m[i][j],咱們注意到m[i][c]表示當揹包重量爲題目中要求的c時揹包的最大價值,那麼在獲得m[i][c]以前,咱們必然是比較了m[i-1][j-w[i]]+v[i]與m[i-1][j]的大小,從而決定是否將物品放入揹包。所 以咱們能夠利用回溯的方法,若m[i][j]=m[i-1][j],那麼物品沒有放入揹包;不然物品必定被放入揹包。所以咱們能夠從最後一件物品開始,一 步一步回退到第一件物品,直到找到全部的物品放入揹包的狀況。本題中物品的裝入狀況如表中紅色和藍色部分所示,其中紅色表示當前物品被裝入揹包,藍色表示 沒有裝入揹包。

代碼實現:

 

[java] view plain copy

 

  1. public class Main {  
  2.     public static void main(String[] args) {  
  3.         int []w={2,2,6,5,4}; //物品重量  
  4.         int []v={6,3,5,4,6}; //物品價值  
  5.         int c=10;            //揹包容量  
  6.         int []x=new int[5];  //記錄物品裝入狀況,0表示不轉入,1表示裝入  
  7.         x[0]=1; //初始值表示第一個物品已裝入揹包  
  8.         int [][]m=new int[5][c+1];//須要維護的二維表,爲了方便計算加入一列,其中第0列表示揹包容量爲0時揹包的最大價值爲0  
  9.         /* 
  10.         * 初始化第一行,即揹包中裝入第一件物品 
  11.         * */  
  12.         for(int j=1;j<=c;j++){  
  13.             if(j>=w[0]){  
  14.                 m[0][j]=v[0];  
  15.             }  
  16.         }  
  17.         /* 
  18.         * 揹包中依次裝入其餘的物品 
  19.         * */  
  20.         for(int i=1;i<5;i++){  
  21.             for(int j=1;j<=c;j++){  
  22.                 if(j<w[i])m[i][j]=m[i-1][j]; //不裝入揹包  
  23.                 else{  
  24.                     if(m[i-1][j-w[i]]+v[i]>m[i-1][j]) m[i][j]=m[i-1][j-w[i]]+v[i]; //選擇價值較大者  
  25.                     else m[i][j]=m[i-1][j];  
  26.                 }  
  27.             }  
  28.         }  
  29.         System.out.println("揹包的最大價值爲:"+m[w.length-1][c]);  
  30.         for(int i=4;i>=1;i--){  
  31.             if(m[i][c]>m[i-1][c]){  
  32.                 x[i]=1; //裝入揹包  
  33.                 c-=w[i]; //物品i裝入揹包以前揹包的容量  
  34.             }  
  35.             else x[i]=0; //沒有裝入揹包  
  36.         }  
  37.         System.out.print("裝入揹包的物品編號是:");  
  38.         for(int i=0;i<5;i++){  
  39.             if(x[i]==1) System.out.printf("%2d",(i+1));  
  40.         }  
  41.     }  
相關文章
相關標籤/搜索