1. 程式人生 > >0-1揹包回溯

0-1揹包回溯

限定條件:

如果放入該物品<剩餘揹包容量則回溯。

如果當前價值+剩餘容量下剩餘物品的最大價值<當前最大價值則回溯。(剩下在怎麼放都不會比當前最大價值大,就沒必要算了)

測試:

第一行分別輸入物品數量n與揹包容量c

用例:

10 300
95 89
75 59
23 19
73 43
50 100
22 72
6 44
57 16
89 7
98 64

測試結果:

388

程式碼:

 1 /*測試用例結果388 
 2 10 300
 3 95 89
 4 75 59
 5 23 19
 6 73 43
 7 50 100
 8 22 72
 9 6 44
10 57 16
11 89 7
12 98 64
13 */ 14 #include<stdio.h> 15 #include<stdlib.h> 16 int n,c;//物品數量,揹包容量 17 int w[300],v[300]; //物品重量,物品價值。 18 float u[300][2]; 19 float U[300];//物品單位價值。 20 int max = 0; //當前最大價值 21 int num = 0;//遞迴次數 22 int cmp(const void *a,const void *b){//排序從大到小 23 return ((float*)a)[1]>((float*)b)[1]?-1:1; 24 }
25 float f1(int i,int weight);//返回剩餘最大價值 26 void f(int i,int weight,int val);//求最大價值 27 int main(){ 28 scanf("%d %d",&n,&c); 29 int w1[300],v1[300]; 30 for(int i=0;i<n;i++){//輸入每個物品質量與價值 31 scanf("%d",&w1[i]); 32 scanf("%d",&v1[i]); 33 } 34 for(int i=0;i<n;i++){//
獲得單位價值 35 u[i][0] = i; 36 u[i][1] = (float)v1[i]/w1[i]; 37 } 38 qsort(u,n,sizeof(u[0]),cmp);//單位價值排序 39 for(int i=0;i<n;i++){//排序物品 40 w[i] = w1[(int)u[i][0]]; 41 v[i] = v1[(int)u[i][0]]; 42 U[i] = u[i][1]; 43 } 44 f(0,0,0); 45 printf("%d\n",max); 46 printf("遞迴次數:%d",num); 47 } 48 void f(int i,int weight,int val){//i表示第i個物品,weight表示當前重量,val表示當前價值。 49 num++; 50 if(i==n){//判斷到第n個物品 51 if(weight<=c) max = max>val?max:val;//返回當前價值和最大價值的最大者。 52 return; 53 } 54 //右子樹的進入條件 即放入當前物品 55 //if(weight+w[i]<=c&&f1(i,c-weight)+val>max)//當剩餘揹包容量不足,或者當前價值+當前剩餘最大價值<當前最大值,減去右子樹。 56 f(i+1,weight+w[i],val+v[i]); 57 //不放入當前物品 58 f(i+1,weight,val); 59 } 60 float f1(int i,int weight){//剩餘最大價值。 61 float sum = 0; 62 while(weight>=w[i]&&i<n){ 63 sum += v[i]; 64 weight -= w[i]; 65 i++; 66 } 67 if(i<n&&weight>0){ 68 sum += weight*U[i]; 69 } 70 return sum; 71 }

執行結果:

 

 

 

不剪枝遞迴次數:

 

不考第一個約束條件遞迴次數:

不考慮第二個約束條件:

考慮所有約束條件先放進去:

考慮所有約束條件先不放進去:

可以看出剪枝越多效率越高。且同樣約束條件下先放與不先放遞迴次數不同。一般先放遞迴次數少效率高。