1. 程式人生 > >分支界限法解決0/1揹包問題

分支界限法解決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 }