分支界限法解决0/1背包问题

1.堆

  1 #include<iostream>
  2 #include<algorithm>
  3 using namespace std;
  4 #define N 100 //最多可能物体数
  5 struct goods  //物品结构体
  6 {
  7     int sign;  //物品序号
  8     int w; //物品重量
  9     int p; //物品价值
 10 }a[N];
 11 
 12 bool m(goods a,goods b)
 13 {
 14     return (a.p/a.w)>(b.p/b.w);
 15 }
 16 
 17 int max(int a,int b)
 18 {
 19     return a<b?b:a;
 20 }
 21 
 22 int n,C,bestP=0,cp=0,cw=0;
 23 
 24 int X[N],cx[N];
 25 
 26 struct KNAPNODE   //状态结构体
 27 {
 28     bool s1[N]; //当前放入物体
 29     int k;     //搜索深度
 30     int b; //价值上界
 31     int w; //物体重量
 32     int p; //物体价值
 33 };
 34 
 35 struct HEAP   //堆元素结构体
 36 {
 37     KNAPNODE *p;//结点数据
 38     int b;        //所指结点的上界
 39 };
 40 
 41 //交换两个堆元素
 42 void swap(HEAP &a, HEAP&b)
 43 {
 44     HEAP temp = a;
 45     a = b;
 46     b = temp;
 47 }
 48 
 49 //堆中元素上移
 50 void mov_up(HEAP H[], int i)
 51 {
 52     bool done = false;
 53     if(i!=1){
 54        while(!done && i!=1){
 55            if(H[i].b>H[i/2].b){
 56               swap(H[i], H[i/2]);
 57            }else{
 58               done = true;
 59            }
 60            i = i/2;
 61        }
 62     }
 63 }
 64 
 65 //堆中元素下移
 66 void mov_down(HEAP H[], int n, int i)
 67 {
 68     bool done = false;
 69     if((2*i)<=n){
 70        while(!done && ((i = 2*i) <= n)){
 71            if(i+1<=n && H[i+1].b > H[i].b){
 72               i++;
 73            }
 74 
 75            if(H[i/2].b<H[i].b){
 76               swap(H[i/2], H[i]);
 77            }else{
 78               done = true;
 79            }
 80        }
 81     }
 82 }
 83 
 84 //往堆中插入结点
 85 void insert(HEAP H[], HEAP x, int &n)
 86 {
 87     n++;
 88     H[n] = x;
 89     mov_up(H,n);
 90 }
 91 
 92 //删除堆中结点
 93 void del(HEAP H[], int &n, int i)
 94 {
 95     HEAP x, y;
 96     x = H[i]; y = H[n];
 97     n --;
 98     if(i<=n){
 99        H[i] = y;
100        if(y.b>=x.b){
101            mov_up(H,i);
102        }else{
103            mov_down(H, n, i);
104        }
105     }
106 }
107 
108 //获得堆顶元素并删除
109 HEAP del_top(HEAP H[], int&n)
110 {
111     HEAP x = H[1];
112     del(H, n, 1);
113     return x;
114 }
115 
116 //计算分支节点的上界
117 void bound( KNAPNODE* node,int M, goods a[], int n)
118 {
119     int i = node->k;
120     float w = node->w;
121     float p = node->p;
122     if(node->w>M){   //  物体重量超过背包载重量
123        node->b = 0;   //  上界置为0
124     }else{
125        while((w+a[i].w<=M)&&(i<n)){  
126            w += a[i].w;   // 计算背包已装入载重
127            p += a[i++].p; //    计算背包已装入价值
128        }
129        if(i<n){
130            node->b = p + (M - w)*a[i].p/a[i].w;
131        }else{
132            node -> b = p;
133        }
134     }
135 }
136 
137 //用分支限界法实现0/1背包问题
138 int KnapSack4(int n,goods a[],int C, int X[])
139 {
140     int i, k = 0;      // 堆中元素个数的计数器初始化为0
141     int v;
142     KNAPNODE *xnode, *ynode, *znode;
143     HEAP x, y, z, *heap;
144     heap = new HEAP[n*n];        // 分配堆的存储空间
145     for( i=0; i<n; i++){
146        a[i].sign=i;        //记录物体的初始编号
147     }
148     sort(a,a+n,m);             // 对物体按照价值重量比排序
149     xnode = new KNAPNODE;        // 建立父亲结点
150     for( i=0; i<n; i++){           //  初始化结点
151        xnode->s1[i] = false;
152     }
153     xnode->k = xnode->w = xnode->p = 0;
154     while(xnode->k<n) {
155        ynode = new KNAPNODE;     // 建立结点y
156        *ynode = *xnode;         //结点x的数据复制到结点y
157        ynode->s1[ynode->k] = true;     //  装入第k个物体
158        ynode->w += a[ynode->k].w;     //  背包中物体重量累计
159        ynode->p += a[ynode->k].p;     //  背包中物体价值累计
160        ynode->k ++;               //  搜索深度++
161        bound(ynode, C, a, n); //       计算结点y的上界
162        y.b = ynode->b;
163        y.p = ynode;
164         insert(heap, y, k);        //结点y按上界的值插入堆中
165        znode = new KNAPNODE;     // 建立结点z
166        *znode = *xnode;          //结点x的数据复制到结点z
167        znode->k++;                         //   搜索深度++
168        bound(znode, C, a, n); //计算节点z的上界
169        z.b = znode->b;
170        z.p = znode;
171        insert(heap, z, k);     //结点z按上界的值插入堆中
172        delete xnode;
173        x = del_top(heap, k);   //获得堆顶元素作为新的父亲结点
174        xnode = x.p;
175     }
176     v = xnode->p;
177     for( i=0; i<n; i++){     //取装入背包中物体在排序前的序号
178        if(xnode->s1[i]){
179            X[a[i].sign] =1 ;
180        }else{
181            X[a[i].sign] = 0;
182        }
183     }
184     delete xnode;
185     delete heap;
186     return v;              //返回背包中物体的价值
187 }
188 
189 /*测试以上算法的主函数*/
190 int main()
191 {
192     goods b[N];
193     printf("物品种数n: ");
194     scanf("%d",&n);   //输入物品种数
195     printf("背包容量C: ");
196     scanf("%d",&C);   //输入背包容量
197     for (int i=0;i<n;i++)    //输入物品i的重量w及其价值v
198     {
199        printf("物品%d的重量w[%d]及其价值v[%d]:  ",i+1,i+1,i+1);
200        scanf("%d%d",&a[i].w,&a[i].p);
201        b[i]=a[i];
202     }
203 
204 int sum4=KnapSack4(n,a,C,X);//调用分支限界法求0/1背包问题
205     printf("分支限界法求解0/1背包问题:\nX=[ ");
206     for(i=0;i<n;i++)
207        cout<<X[i]<<" ";//输出所求X[n]矩阵
208     printf("]  装入总价值%d\n",sum4);
209     return 0;
210 }

2.队列

 1 /*队列式分支限界法解0-1背包问题*/
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 
 5 const int maxn = 1e5+7;
 6 struct node{
 7     int weight, value, level, flag;
 8 };
 9 queue<node> q;
10 
11 int inque(int w,int v,int level,int flag,int n,int* MaxValue){
12     node now;
13     now.weight = w;
14     now.value = v;
15     now.level = level;
16     now.flag = flag;
17     if (level == n){
18         if (now.value > *MaxValue){
19             *MaxValue = now.value;
20         }
21         return 0;
22     }
23     else
24         q.push(now);
25 }
26 
27 int solve(int w[],int v[],int n,int c,int* MaxValue){
28     int i = 1;
29     node now, last;
30     last.weight = 0; last.value = 0; last.level = 1; last.flag = 0;
31     now.weight = -1; now.value = 0; now.level = 0; now.flag = 0;
32     q.push(now);
33     while(1){
34         if(last.weight + w[i - 1] <= c){
35             inque(last.weight + w[i - 1], last.value + v[i - 1], i, 1,n,MaxValue);
36         }
37         inque(last.weight,last.value, i, 0, n, MaxValue);
38         last = q.front();
39         q.pop();
40         if(last.weight == -1){
41             if (q.empty() == 1)
42                 break;
43             last = q.front();
44             q.pop();
45             q.push(now);
46             i++;
47         }
48 
49     }
50     return 0;
51 }
52 
53 int main(){
54     int w[maxn] = { 16, 15, 15 };
55     int v[maxn] = { 45, 25, 25 };
56     int n = 3;
57     int c = 30;
58     /*
59     while(cin >>n >> c){
60         for(int i = 0;i < n;i++){
61             cin >> w[i] >> v[i];
62         }
63     }
64     */
65     int MaxValue = 0;
66     solve(w, v, n, c, &MaxValue);
67     cout << MaxValue <<endl;
68     return 0;
69 }

猜你喜欢

转载自www.cnblogs.com/ouyang_wsgwz/p/9949263.html
今日推荐