zoukankan      html  css  js  c++  java
  • 回溯之0-1背包

    0-1背包问题:物品总数n,每个物品的体积w[i],价值v[i],给定背包的总容量W,求放入背包中物品的最大价值。0-1背包回溯背景和思路是这样的:

    用回溯法对0-1背包问题进行求解,具体思路是:

    1.使用解空间进行标记每个物品的放入情况,即要建立一个数组进行保存其是否放入,可使用 bool  x[i]进行标识;

    2.回溯法第一感觉上是穷举所有情况,但事实上,有好多种情况可以进行避免,即若第t个物品放入后(即x[t]=1)已经超出背包重量,那么,在x[t]=1情况下的t+1—n个物品就不用再考虑,这样可以节省好多时间,回溯法有区别与穷举法;

    3.对于解空间,用解空间数进行组织数据,解空间树的深度就是问题的规模n;

    4.在解空间树中,我们用左子树、右子树分别标记1/0情况,即左子树的边代表放入,右子树的边代表不放入;

    5.建立回溯函数是重中之重,回溯函数建立有三步(判断是否到达叶节点,约束条件(这里是基于重量),限界剪枝(剩余价值是否大于最优,否则没有算下去的必要了))

    具体的实现如下:

     1 #include <iostream>
     2 #define N 100
     3 using namespace std;
     4 int n;
     5 double W;
     6 double w[N];
     7 double v[N];
     8 bool x[N];  //用于记录某次回溯情况
     9 bool best_x[N]; //存储最优回溯情况
    10 double now_v;   //当前价值
    11 double remain_v;    //剩余价值
    12 double now_w;   //当前容量
    13 double best_v;  //最优价值
    14 
    15 //计算剩余价值
    16 double Bound(int k){
    17     remain_v = 0;
    18     while (k <= n) {
    19         remain_v += v[k];
    20         k++;
    21     }
    22     return remain_v + now_v;
    23 }
    24 //剪枝的三个判定
    25 void Backtrack(int t){
    26     if (t > n) {  //是否到达叶节点
    27         for (int i = 1; i <= n; i++) {
    28             best_x[i] = x[i];   //记录回溯的最优情况
    29         }
    30         best_v = now_v; //记录回溯中的最优价值
    31         return;
    32     }
    33     if (now_w + w[t] <= W) {  //约束条件,是否放入。放入考虑左子树,否则考虑右子树
    34         x[t] = 1;
    35         now_w += w[t];
    36         now_v += v[t];
    37         Backtrack(t + 1); //进行下一个节点的分析
    38         now_w -= w[t];  //在到达叶节点后进行回溯
    39         now_v -= v[t];
    40     }
    41     if (Bound(t + 1) > best_v) {    //限界条件,是否剪枝。若放入t后不满足约束条件则进行到此处,然后判断若当前价值加剩余价值都达不到最优,则没必要进行下去
    42         x[t] = 0;
    43         Backtrack(t + 1);
    44     }
    45 }
    46 //实现价值最优
    47 void Knapsack(double W, int n){
    48     double sum_w = 0;
    49     double sum_v = 0;
    50     best_v = 0;
    51     for (int i = 0; i < n; i++) {
    52         sum_w += w[i];
    53         sum_v += v[i];
    54     }
    55     if (sum_w <= W) {
    56         best_v = sum_v;
    57         cout << "These goods could be put in the shopping car";
    58         cout << "The best value is:" << best_v << endl;
    59         return;
    60     }
    61     Backtrack(1);
    62     cout << "The best value is:" << best_v << endl;
    63     cout << "The condiction of these goods are:" << endl;
    64     for (int i = 1; i <= n; i++) {
    65         cout << i << " ";
    66         cout << best_x[i] << endl;   //打印所有物品的放入情况,若为1表示放入,若为0则表示不放入
    67     }
    68 }
    69 int main(){
    70     cout << "Please input the num of goods:";
    71     cin >> n;
    72     cout << "Please input the capacity of the shopping car:";
    73     cin >> W;
    74     cout << "Please input thier weights and values in order:" << endl;
    75     for (int i = 1; i <= n; i++) {
    76         cin >> w[i] >> v[i];
    77     }
    78     Knapsack(W, n);
    79     return 0;
    80 }
  • 相关阅读:
    什么是MongoDb
    Python之人工智能:PyAudio 实现录音 自动化交互实现问答
    Python人工智能之初识接口
    cordova(安卓)(腾讯信鸽注册绑定与反绑定) 插件开发
    sencha touch 在安卓中横屏、竖屏切换 应用崩溃问题
    Sencha Touch 实战开发培训 电子书 基础篇
    wps 批量调整图片大小 宏
    使用 crosswalk-cordova 打包sencha touch 项目,再也不用担心安卓兼容问题!
    Sencha Cmd 5.0.1.231 是坑爹货
    sencha touch api 使用指南
  • 原文地址:https://www.cnblogs.com/SHNLQS-1273196803/p/11056997.html
Copyright © 2011-2022 走看看