• 分支界限法解决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背包问题:
    X=[ ");
    206     for(i=0;i<n;i++)
    207        cout<<X[i]<<" ";//输出所求X[n]矩阵
    208     printf("]  装入总价值%d
    ",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 }
  • 相关阅读:
    预处理命令
    函数
    结构体
    字符数组
    数组
    文件
    用 typedef 定义类型
    枚举类型
    联合
    位运算
  • 原文地址:https://www.cnblogs.com/ouyang_wsgwz/p/9949263.html
Copyright © 2020-2023  润新知