0-1 揹包問題

咋先不說解決這種揹包問題的方法,個人感覺應該先把產生問題的背景描述出來會比較好一點,如下:

1,問題描述

有N件物品和一個容量爲V的揹包。第i件物品的重量是c[i],價值是w[i]。求解將哪些物品裝入揹包可使這些物品的重量總和不超過揹包容量,且價值總和最大。,

2,具體實例:

現有一個容量爲10kg的揹包,還有5件不同質量和價格的物品,現在讓你,把這些物品有選擇性的放到揹包裏面,使得揹包的價值最大且揹包裏物品的重量不能超過揹包的最大容量。5件物品的重量分別爲{A,B,C,D,E}與之對應的質量分別爲{2,2,6,5,4}對應的價格爲{6,3,5,4,6}。

問題特點:

每種物品僅有一件,可以選擇放或不放。

解決問題思路:

我把揹包容量從0列舉到10,因爲揹包容量太大,所以求解很複雜。故此,我就分別求,看揹包容量分別爲0,1,2,3....10時,怎樣放物品能使不同容量的揹包價值最大。放物品的時候也是一個一個的放,至於是否放得進去,看如下例子:

(想了好久也不知道該怎麼敘述,這裏我就直接舉例說明,看我基友能不能看懂,要是他能看懂的話我,相信你們就能看懂)

現在,我準備把物品A往揹包裏面放,容易看出,揹包容量爲0和1時,物品A是放不進去的,所以價值爲0,當揹包容量爲2,3,4....10時可以放進去,且與之對應的價值都是6,這應該好理解吧,就是說,揹包容量爲2時,把A放進去,揹包滿了,價值爲6,容量爲3時,A放進去時,揹包沒滿,但價值還是6,以此類推後面的容量對應的價值都是6。如圖,

 

現在,在以上操作的基礎上(物品A放入相應容量的揹包中使得揹包的價值最大)再把物品B放入相應容量的揹包中,由於B的重量爲也是2,所以揹包容量爲0和1時不能放B,所以對應的價值,應該是上一次(放入A)時的最大價值,結果還是0,然後容量爲2時,做出判斷,如果放入B,揹包滿了不能放A了,價值是3,如果不放B,那麼價值就是A的價值6,很顯然6大於3   所以這兒應該放A,然後一直往後放,容量爲4時,可以把A和B都放進去,價值爲9,以後容量爲5,6,7,8,9,10價值都是9  如下圖


好了,現在可以把C也放進去了如圖


最後把D和E也放進去


至此,所有的物品都已有選擇性的放進去了,但是你還不知道到底哪個是真的放進去了,哪個沒放進

不過,最大值可以看出來,就是15

找出最優解:

判斷放進去的物品:

我們從最大值開始判斷,揹包容量爲10時,(有選擇性的放或不放E後)價值最大爲15,(有選擇性的放D或不放D後)價值最大爲14,這就說明了一個問題,要是沒有放E,那麼最大價值應該是14,所以確定E肯定放進去了。

然後判斷D是否放入了揹包,判斷D時,先把E的重量減掉(因爲E已經確定放進去了,所以接下來判斷的就是剩餘揹包容量中是否放入了D),10-4=6,看揹包容量爲6時的情況,有圖可以看出,對D沒有進行任何操作時的價值爲9(看C行,容量爲6的那個價值),然後對D進行 ”有選擇性的放或不放“ 的操作後,價值還是9,那說明D肯定沒放,

對C判斷,同樣的,先算出剩餘揹包容量,由於已近確定放E,沒放D,所以剩餘揹包容量爲10-4=6,有圖可知,對C沒有進行任何操作時的價值爲9(看B行,容量爲6的那個價值),然後對C進行 ”有選擇性的放或不放“ 的操作後,價值還是9,那說明C肯定沒放,

對B判斷,以上可知,C,D都沒放,放入了E,揹包剩餘容量還是6,對B沒有進行任何操作時的價值爲6(看A行,容量爲6的那個價值),然後對B進行 ”有選擇性的放或不放“ 的操作後,價值是9,那說明C肯定放進去了,

對A判斷,以上可知剩餘揹包容量爲10-4-2=4,對A沒有進行任何操作時的價值爲0(啥都不操作的時候),然後對A進行 ”有選擇性的放或不放“ 的操作後,價值是6,那說明A肯定放進去了,

至此我們可以得出我們的最優解揹包裏放進去的物品分別是A,B,E,還可以知道,揹包容量爲2+2+4=8時,揹包的價值就已經達到最大了。

下面附上代碼

#include<stdio.h>  
#include<stdlib.h>  
#include<iostream>  
using namespace std;  
const int c = 10;             //揹包的容量  
const int w[] = {0,2,2,6,5,4};//物品的重量,其中0號位置不使用 。   
const int v[] = {0,6,3,5,4,6};//物品對應的待加,0號位置置爲空。  
const int n = sizeof(w)/sizeof(w[0]) - 1 ; //n爲物品的個數   
int x[n+1];  
void package0_1(int m[][11],const int w[],const int v[],const int n)//n代表物品的個數  用於進行“有選擇性放或不放物品” 的操作
{  
    //採用從底到頂的順序來設置m[i][j]的值  
    //首先放w[n]  
	int i,j;
    memset(m,0,sizeof(m));
    for(i = 1; i <= n; i++)  
	{
        for( j = 0; j <= c; j++)  
		{
           
           m[i][j] = m[i-1][j];//如果j < w[i]則,當前位置就不能放置,它等於上一個位置的值。  
                                            //否則,就比較到底是放置之後的值大,還是不放置的值大,選擇其中較大者。 
		   if(j>=w[i])
		   {
                m[i][j] = m[i-1][j] > m[i-1][j-w[i]] + v[i]?   
                m[i-1][j] : m[i-1][j-w[i]] + v[i]; 
		   }
		}
	}
}  
void answer(int m[][11],const int n)  //選出最優解,判斷那個放入了揹包,那個沒有放,
{  
    int j = c;  
    int i;  
    for(i = n; i>=1; i--)  
        if(m[i][j] == m[i-1][j])
			x[i] = 0;  
        else                
		{   
            x[i] = 1;  
            j = j - w[i];  
        }  
}  
int main()  
{  
 int m[6][11];
 memset(m,0,sizeof(m));
 package0_1(m,w,v,n);  
 for(int i = 0; i <= 5; i++)  
 {  
     for(int j = 0; j <= 10; j++) 
		 if(i==0)
	printf("%2d ",j);
		 else
     printf("%2d ",m[i][j]);  
    printf("\n");   
 }   
 answer(m,n);  
 printf("The best answer is:\n"); 
 for( i = 1; i <= 5; i++)  
	 printf("%d ",x[i]);
 system("pause");  
 return 0;  
}  

  1.  m[i][j] = m[i-1][j] > m[i-1][j-w[i]] + v[i]?     
  2.                 m[i-1][j] : m[i-1][j-w[i]] + v[i];   
深度分析上述表達式

對於該式子的理解,首先得清楚一點就是每個物品只有兩種狀態  放或不放  例如那物品A和B來說,相互組合之後有三種情況

(1)放A不放B   (2)放B不放A   (3)即放A又放B

其中怎麼判斷到底選擇哪種放發 主要就看上面這個公式,看左面,其中m [i-1] [j]表示的就是放A不放B時的揹包的價值  m[i-1][j-w[i]]+v[i]這個式子有兩層意思:只放B    A與B都放,具體的實現就要看是否滿足對應的條件了,這裏面,給我的感覺是,它直接假設把第i(這裏是物品B)個物品放進去,下面我給你分析一下:


放B後(第i個物品),那麼揹包剩餘的質量就是j-w[i],然後看前i-1(在這裏只有物品A)個物品在剩餘的揹包質量中的價值是多少,即m[i-1][j-w[i]]。最後加上物品第i個(這裏是物品B)物品的價值v[i],最終的公式是m[i-1][j-w[i]]+v[i]

j=2,3時

具體的例子是,現在開始放B,即判斷m[2][j](j的範圍是0到10)的值,我們一個一個的判斷,因爲B的質量爲2,所以只有揹包的質量等於2 時纔開始進行方與不放的操作,那麼現在使m[2][2]等於m[1][2]還是m[1][0]+v[1]   這裏面m[1][2]的意思就是放A不放B ,那麼價值就是A的價值=6,然後看m[1][0]+v[1]這裏我前面說了,直接假設把B放進去,那麼揹包剩餘質量爲j-w[i]=0,由此可知前i-1個物品(在這裏只有A)是放不進去的,那麼價值爲0,然後加上第i個物品的價值v[i]=3,所以最終的價值m[i-1][j-w[i]]+v[i]=3其中表達的意思是放B不放A,最終判斷m[1][2]=6大於m[1][0]+v[1]=3所以m[2][2]=6,後面的j=3,判斷方法於此一樣

j=4,5,6,7,8,9,10時

這裏,再說一下j=4時的情況,現在使m[2][4]等於m[1][4]還是m[1][2]+v[4]   這裏面m[1][4]的意思就是放A不放B ,那麼價值就是A的價值=6,然後看m[1][2]+v[4]這裏我前面說了,直接假設把B放進去,那麼揹包剩餘質量爲j-w[i]=2,由此可知前i-1個物品(在這裏只有A)是可以放進去的,那麼價值爲6,然後加上第i個物品的價值v[4]=3,所以最終的價值m[i-1][j-w[i]]+v[i]=9其中表達的意思是A和B都放進去,最終判斷m[1][4]=6小於m[1][2]+v[4]=9所以m[2][4]=9.後面的j=5,6,7,8,9,10 的判斷方法於此一樣




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章