0-1揹包回溯
阿新 • • 發佈:2018-11-04
限定條件:
如果放入該物品<剩餘揹包容量則回溯。
如果當前價值+剩餘容量下剩餘物品的最大價值<當前最大價值則回溯。(剩下在怎麼放都不會比當前最大價值大,就沒必要算了)
測試:
第一行分別輸入物品數量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 6413 */ 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 }
執行結果:
不剪枝遞迴次數:
不考第一個約束條件遞迴次數:
不考慮第二個約束條件:
考慮所有約束條件先放進去:
考慮所有約束條件先不放進去:
可以看出剪枝越多效率越高。且同樣約束條件下先放與不先放遞迴次數不同。一般先放遞迴次數少效率高。