0-1背包回溯
Posted lolybj
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 ",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 }
运行结果:
不剪枝递归次数:
不考第一个约束条件递归次数:
不考虑第二个约束条件:
考虑所有约束条件先放进去:
考虑所有约束条件先不放进去:
可以看出剪枝越多效率越高。且同样约束条件下先放与不先放递归次数不同。一般先放递归次数少效率高。
以上是关于0-1背包回溯的主要内容,如果未能解决你的问题,请参考以下文章