0-1背包問題——動態規劃法

來源:互聯網
上載者:User

標籤:0-1背包   動態規劃   演算法   

問題描述:給定n種物品和一背包。物品i的重量是w[i],其價值為v[i],背包的容量為C。問應如何選擇裝入背包的物品,使得裝入背包中物品的總價值最大?
分析:對於一種物品,要麼裝入背包,要麼不裝。所以對於一種物品的裝入狀態可以取0和1。設物品i的裝入狀態為xi,xi∈ (0,1),此問題稱為0-1背包問題。
資料:物品個數n=5,物品重量w[5]={2,2,6,5,4},物品價值v[5]={6,3,5,4,6},總重量c=10。背包的最大容量為10,那麼在設定數組m大小時,可以設行列值為5和10,那麼,對於m(i,j)就表示可選物品為i到n且背包容量為j(總重量)時背包中所放物品的最大價值。看下面這個表格即為動態規劃法解0-1背包問題的過程:

表格中灰色的為序號:列的1~5表示5個物品,橫向的1~10表示背包的容量,綠色的列表示相對應物品的的重量,淺藍色的一列表示相對應物品的價值。假設建立一個5*10的數組對應圖片中的棕色部分,棕色部分即為求解的過程,具體求解過程如下:
圖上所示的求解過程是從下往上求解,也就是說先分析第5個物品,最後分析第一個物品。當背包中為空白的時候,考慮第5個物品,當背包容量為1, 2, 3的時候這個背包都是裝不下物品5的,因為物品5的重量是4,因此對應的當背包容量為1, 3, 3的時候背包裡面東西的價值(棕色表格裡面的值)也是為0,當背包容量大於等於4的時候背包可以放下物品5,所以背包裡面東西的價值就是6(因為這裡先只考慮只有一件物品5的時候),到此只有物品5的情況已經分析完畢;
接下來分析同時擁有物品5和物品4的情況,當背包容量為1, 2, 3的時候,背包裡面既放不下4物品也放不下5物品,所以背包裡面物品的價值為0,當背包容量大於等於4的時候,至少可以放下物品5了,這個時候就要取捨了,到底是將物品5放進去價值大還是將物品4放進去價值大,當背包容量為4的時候,只能放進去物品5,價值為6,當背包容量為5的時候如果選擇房屋物品4,那麼剩餘的背包容量為0,尋找背包重量為0的列(在前面步驟已經填充過的部分,這裡只填充了第5行第1列的位置),找這一列的最大值為0,所以選擇放物品4的時候背包價值最大為4<不放物品4(剩餘背包容量為5,尋找背包容量5對應的填充過的部分,其最大值為6)時候的6,所以在背包容量為5的時候的最優值是放物品5而不放物品4,一直分析到背包容量為9的時候當選擇放入物品4的時候,剩餘背包容量為4,再尋找背包容量為4時候已經填充過的部分(即最後一行),可以查得最大值為6,所以這個時候選擇放入物品4可以獲得的最大價值為10。...
中間的過程都是如此,這裡再分析一下最後一個物品的放置,背包容量為2的時候,如果放入物品1,獲得的價值為6,剩餘背包容量為0,剩餘背包容量獲得的最大價值為0,所以6+0=6為最大價值,如果不放入1物品,剩餘背包容量為2,剩餘背包容量可以獲得的最大價值為3,所以最優的時候應該是放入物品1;背包容量為3的時候,若放入1物品,獲得價值6,剩餘背包容量1可以獲得的最大價值為0,所以放入物品1可以獲得的最大價值為6,如果不放入物品1,那麼剩餘背包容量3可以獲得的最大價值(在已經填充過的部分尋找)為3,所以這時也是放入物品1為最優......當背包容量為8的時候放入物品1獲得價值6,剩餘背包容量6可以獲得最大價值為9,放入物品1的最大價值為6+9=15,如果不放入物品1,剩餘背包容量8可以獲得的最大價值為9,所以此時也是放入物品1最優。

總結:通過上面的分析過程,可以歸結為:先考慮這個物品放入的時候可以獲得的最大價值(這個物品的價值+剩餘背包(背包總容量-該物品重量)容量可以獲得的最大價值),再考慮不放入這個物品的時候可以獲得的最大價值(剩餘背包容量(此時就是背包總重量)可以獲得的最大價值),然後將2者進行比較,那種結果的價值大就將哪種結果的價值儲存下來,依次類推。

#include<stdio.h>  const int c = 10;             //背包的容量  const int w[] = {2,2,6,5,4};//物品的重量 const int v[] = {6,3,5,4,6};//物品對應的待加  const int n = sizeof(w)/sizeof(w[0]) - 1 ; //n為物品的個數   int x[n];  void package0_1(int m[][10],const int w[],const int v[],const int n)//n代表物品的個數   {      int i, j;/*********************************最後一個物品單獨放置*********************************/      for(j = 1; j <= c; j++)  {       if(j < w[n]) /*背包容量<最後一個物品的重量時*/   m[n][j-1] = 0;          else /*背包能夠放下最後一個物品時*/           m[n][j-1] = v[n];  }         /*********************************放置前n-1個物品*********************************/      for(i = n-1; i >= 0; i--)          for(j = 1; j <= c; j++) {           if(j < w[i])                  m[i][j-1] = m[i+1][j-1];//如果j < w[i]則,當前位置就不能放置,它等於上一個位置的值            else //否則,就比較到底是放置之後的值大,還是不放置的值大,選擇其中較大者   m[i][j-1] = m[i+1][j-1] > m[i+1][j-1-w[i]]+v[i] ? m[i+1][j-1] : m[i+1][j-1-w[i]]+v[i];}}  void answer(int m[][10],const int n)  {      int j = c-1; /*i = 0, j= c-1座標上存放著背包容量為c時的最大價值*/     int i;     for(i = 0; i < n; i++)          if(m[i][j] == m[i+1][j]) x[i] = 0;          else                {   x[i] = 1;  /*如果當前物品放入了背包*/j = j - w[i];  /*重新計算背包剩餘容量,以計算在取最優時其他物品的取捨情況*/        }i -= 1;    x[n] = m[i][j] ? 1 : 0;   }  int main()  {   int m[6][10]={0};  int i, j;    package0_1(m,w,v,n);   for(i = 0; i <= 4; i++)   {       for(j = 0; j < 10; j++)       printf("%3d ",m[i][j]);       printf("\n"); }    answer(m,n);   printf("The best answer is:\n");   for(i = 0; i < 5; i++)  printf("%d ",  x[i]);  printf("\n"); return 0;  }  


程式運行結果如下:


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.