zoukankan      html  css  js  c++  java
  • [C++11][算法][穷举]输出背包问题的所有可满足解

    关于背包问题的题目,前人之述备矣,这里只讨论实现

    输入:

    n

    ca

    w_1 v_1

    w_2 v_2

    ...

    w_n v_n

    其中,n是物品总数,ca是背包大小,w_n是第n个物品的重量,v_n是第n个物品的价值

    输出:

    v_1 x

    v_2 x

    v_3 x

    ...

    其中,v_n是当前情况为x时背包的价值,x是一串序列,由0,1组成,表示是否放入背包

    如: 1001就表示第一个和最后一个物品放入背包,中间两个物品不放入

    要求编写一个程序,输出所有可满足解.

    思路很简单,就是穷举.穷举每一个情况.

    伪代码如下:

    f() {
      if (没有可以放进背包的东西) {
        输出
      } else {
        放进背包
        f()
        不放进背包
        f()
        恢复原状
      }
    }

    这样,就构造了一个二叉树,可以输出每一种可选解的情况.

    我的代码如下:

     1 #include <iostream>
     2 #include <functional>
     3 
     4 struct Pack {
     5   unsigned cnt;
     6   unsigned *w; // weights
     7   unsigned *v; // values
     8   unsigned *x; // put in or not
     9   unsigned ca; // capacity
    10   
    11   Pack(unsigned items_cnt) : cnt(items_cnt) {
    12     w = new unsigned [items_cnt];
    13     v = new unsigned [items_cnt];
    14     x = new unsigned [items_cnt];
    15     
    16     for (int i = 0; i < items_cnt; ++i) {
    17       w[i] = v[i] = x[i] = -1;
    18     }
    19   }
    20   
    21   ~Pack() {
    22     delete [] w;
    23     delete [] v;
    24     delete [] x;
    25   }
    26 };
    27 
    28 
    29 int main() {
    30   unsigned c;
    31  
    32   std::cin >> c;
    33   
    34   Pack p(c);
    35   
    36   std::cin >> p.ca;
    37   
    38   for (int i = 0; i < p.cnt; ++i) {
    39     std::cin >> p.w[i] >> p.v[i];
    40   }
    41  
    42  
    43  
    44  
    45   std::function<unsigned()> totval = [&]() {
    46     unsigned cnt = 0;
    47     
    48     for (int i = 0; i < p.ca; ++i) {
    49       if (p.x[i] == 1) cnt += p.v[i];
    50     }
    51     
    52     return cnt;
    53   };
    54   
    55   std::function<unsigned()> totwt = [&]() {
    56     unsigned cnt = 0;
    57     
    58     for (int i = 0; i < p.ca; ++i) {
    59       if (p.x[i] == 1) cnt += p.w[i];
    60     }
    61     
    62     return cnt;
    63   };
    64   
    65   std::function<void()> loop = [&]() {
    66     unsigned no = -1;
    67     for (int i = 0; i < p.cnt; ++i) {
    68       if (p.x[i] == -1) {
    69         no = i;
    70         break;
    71       }
    72     }
    73     
    74     if (no == -1) {
    75       std::cout << totval() << ' ';
    76       for (int i = 0; i < p.cnt; ++i) {
    77         std::cout << p.x[i];
    78       }
    79       std::cout << std::endl;
    80     } else {
    81       p.x[no] = 0;
    82       loop();
    83       
    84       p.x[no] = 1;
    85       
    86       if (totwt() <= p.ca) {
    87         loop();
    88       }
    89       
    90       p.x[no] = -1;
    91     }
    92   };
    93   
    94   loop();
    95  
    96   return 0;
    97 }

     测试数据:

    5
    15
    9 8
    1 2
    3 8
    1 0
    3 9

    输出:

    0 00000
    9 00001
    0 00010
    9 00011
    8 00100
    17 00101
    8 00110
    17 00111
    2 01000
    11 01001
    2 01010
    11 01011
    10 01100
    19 01101
    10 01110
    19 01111
    8 10000
    17 10001
    8 10010
    17 10011
    16 10100
    25 10101
    16 10110
    10 11000
    19 11001
    10 11010
    19 11011
    18 11100
    18 11110

    可以找到最优解,10101.

  • 相关阅读:
    WeTagger不封号的微信客服工具(一)——预告
    WeSender不封号的微信群发软件(六)——升级:第六版已经完成
    .net core系列(一)
    .net core系列整理收藏
    Ansible Windows模块学习
    Windows配置Ansible Host
    Alembic管理Sqlite3数据库版本
    高端VIPRION实物图
    Calendar 类 set() 方法使用要点
    Java 日期处理工具类
  • 原文地址:https://www.cnblogs.com/jt2001/p/packquestionall.html
Copyright © 2011-2022 走看看