回溯法-01背包问题之一:递归模式

一、回溯法

回溯法是一个既带有系统性又带有跳跃性的搜索算法。它在包含问题的所有解的解空间树中按照深度优先的策略,从根节点出发搜索解空间树。算法搜索至解空间树的任一节点时,总是先判断该节点是否肯定不包含问题的解。如果肯定不包含,则跳过对以该节点为根的子树的系统搜索,逐层向其原先节点回溯。否则,进入该子树,继续按深度优先的策略进行搜索。

运用回溯法解题通常包含以下三个步骤:

· 针对所给问题,定义问题的解空间;

· 确定易于搜索的解空间结构;

· 以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索;

二、01背包问题描述

01背包问题,即向容量为M的背包装载物品,要么放入要么不放入。从n个物品中选取装入背包的物品,物品i的重量为Wi,价值为Pi。最佳装载指装入的物品价值最高,即∑PiXi(i=1..n)取最大值。约束条件为∑WiXi≤M且Xi∈[0,1](1≤i≤n)。

在这个表达式中,需求出Xi的值。Xi=1表示物品i装入背包,Xi=0表示物品i不装入背包。

· 即判断可行解的约束条件是:∑WiXi≤M(i=0..n),Wi>0,Xi∈[0,1](1≤i≤n)

· 目标最大值:max∑PiXi(i=0..n-1),Pi>0,Xi=0或1(0≤i<n)

0/1背包问题是一个自己选取问题,适合于用子集树表示0/1背包问题的解空间。在搜索解空间树时,只要左儿子节点是一个可行节点,搜索就进入左子树,在右子树中有可能包含最优解才进入右子树搜索,否则将右子树剪去。

三、关于剪枝函数

设当前剩余物品价值总和为r,当前结点x价值为cp,当前x结点上界函数值为bp。L为当前已搜索到的答案结点中受益的最大值,当cp+r=bp<L时可剪去以X为根的子树。

计算右子树中解上界方法是将剩余物品按单位重量价值排序,一次放入物品直至装不下为止,再装入部分未装入物品直至装满背包,由此得到的价值是右子树解上界。

四、递归实现

如下图1所示为01背包问题递归实现的示意图,图2是01背包问题递归实现的流程图,描述了代码实现方案。

                                 

图1 01背包问题递归描述图                                     图2 01背包问题递归实现流程图

图1比较容易理解,是否已拿完物品也就是i<n(i是当前物品序号,n是物品总数目)是否成立,如果成立则递归结束并打印输出路径。如果i<n则判断第i个物品能否放入背包,如果不能放入,则考虑放置i+1个物品,如果能放入还存在当前第i个放入和不放入两种情形后对第i+1个的影响。注意在“放入还是不放入”的部分可考虑加入剪枝函数。

五、递归的代码实现

代码1 Main函数测试代码:

public static void Main (string[] args)
		{
            Obj[] objs = new Obj[4];
            objs[0] = new Obj() { Weight = 7, Price = 42 };
            objs[1] = new Obj() { Weight = 3, Price = 12 };
            objs[2] = new Obj() { Weight = 4, Price = 40 };
            objs[3] = new Obj() { Weight = 5, Price = 25 };

            Backtracking_Recursion1 r = new Backtracking_Recursion1();
            r.W = 10;
            r.objs = objs;
            r.Backtracking(0);

            Console.Read();
		}

代码2Obj物品代码

public class Obj
    {
        /// <summary>
        /// 物品重量
        /// </summary>
        public int Weight
        {
            get;
            set;
        }
        /// <summary>
        /// 物品价值
        /// </summary>
        public int Price
        {
            get;
            set;
        }
        /// <summary>
        /// 该物品是否放入包内
        /// </summary>
        internal bool Selected
        {
            get;
            set;
        }
    }

代码3递归实现01背包问题

class Backtracking_Recursion1
    {
        #region field
        protected int m_currentWeight = 0;
        protected int m_currentPrice = 0;
        #endregion
        #region property
        /// <summary>
        /// 背包容量
        /// </summary>
        /// <value>默认20</value>
        public int W
        {
            get;
            set;
        }

        public int n
        {
            get
            {
                return objs == null ? 0 : objs.Length;
            }
        }

        /// <summary>
        /// 物品,包括重量/价值和数量
        /// </summary>
        /// <value>The objects.</value>
        public Obj[] objs
        {
            get;
            set;
        }
        #endregion
        public void Backtracking(int i)
        {
            if (i >= n)
            {
                Printing();
                return;
            }

            if (objs[i].Weight + m_currentWeight <= W)
            {
                m_currentWeight += objs[i].Weight;
                m_currentPrice += objs[i].Price;
                objs[i].Selected = true;

                Backtracking(i + 1);

                m_currentPrice -= objs[i].Price;
                m_currentWeight -= objs[i].Weight;
            }
            objs[i].Selected = false;
            Backtracking(i + 1);
        }

        /// <summary>
        /// 输出路径
        /// </summary>
        protected void Printing()
        {
            Console.Write("<");
            for (int i = 0; i < objs.Length; i++)
            {
                Console.Write(objs[i].Selected ? "1 " : "0 ");

            }
            Console.WriteLine(">, price: " + m_currentPrice.ToString()
                               + "\t weight: " + m_currentWeight.ToString());
        }
    }

六运行结果

注:

1 代码3中Printing()函数调用后可判断并记录最优路径;

2 下文将讲述01背包问题回溯法的顺序执行方法,并通过模板模式整合两种不同的实现方案。

回溯法-01背包问题之一:递归模式,布布扣,bubuko.com

时间: 2024-10-08 10:17:36

回溯法-01背包问题之一:递归模式的相关文章

回溯法-01背包问题之二:顺序执行模式

上文已讲述了回溯法以及01背包问题的原理,本文讲述如何顺序执行解决01背包问题以及通过模板模式重构软件. 一.顺序执行流程图 图1无剪枝函数的01背包问题顺序执行算法流程图 图2 有剪枝函数的01背包问题顺序执行算法流程图 无剪枝函数是通用的深度遍历算法,为了减少搜索深度可通过剪枝函数处理完全不可能的分枝.与递归方案的区别主要表现在i>=n后需要"回溯",即用后进先出的方式将物品逐个拿出. 二.执行代码 递归与顺序执行方法仅仅是实现方法Backtracking(int i)不同,

回溯法--0-1背包问题

算法描述: 0-1背包的回溯法,与装载问题的回溯法十分相似.在搜索解空间树时,只要其左儿子结点是一个可行结点,搜索就进入其左子树.当右子树中有可能包含最优解时才进入右子树进行搜索.否则将右子树剪去. 计算右子树上界的更好算法是: 将剩余物品依其单位重量价值排序,然后依次装入物品,直至装不下时,再装入该物品的一部分而装满背包. 算法实现: 由Bound函数计算当前节点处的上界. 类Knap的数据成员记录解空间树的节点信息,以减少参数传递及递归调用所需的栈空间. 在解空间树的当前扩展结点处,仅当要进

利用回溯法求解背包问题

最近看完了利用回溯法求八皇后问题,最后成功求解到92种解法,然后在看利用贪心求解背包问题,突然想到其实也可以利用回溯法求解背包问题,本质上回溯法是一个穷举的方式在求. 回溯法求解出的结果肯定是正确的,这也可以验证自己所写的贪心算法的正确性. 问题描诉: 设定Wmax为最大重量,W[](0~n-1)为编号0~n-1的货物重量,V[](0~n-1)为其价值,x[]为其中解, 在wn=ΣXi*Wi<Wmax的条件下,求Vmax=ΣXi*Vi. 代码如下: //全局变量最大价值int maxvalue=

0-1背包问题(递归实现)

</pre><pre class="cpp" name="code"><span style="font-size:14px;">#include<iostream> #include<vector> #include<iterator> #include<algorithm> #include<string> using namespace std;

回溯法解背包问题分析

先亮出题目: 一,背包问题 及 回溯法解其问题的伪代码 二,赋值后的具体实例 三,如何看懂伪代码 (1)真正了解回溯法的核心思想 我总结的回溯法解题步骤: <1>先找出第一个解 <2>回溯 (2)回溯法核心思想 + 伪代码 + 图9-5 树结构来分析 四,伪代码代入值解析 核心:先找到第一个解,再回溯. cw=0;//背包当前重量 初始值 cp=0;//背包当前价值 初始值 k=1;//第一个物品 n=8;//共8个物品 W=110 第一步:得出第1个可行解: (1)k=1 k=1

回溯法~0-1背包的实现

1 package 背包; 2 3 4 import java.util.ArrayList; 5 import java.util.Collections; 6 import java.util.Comparator; 7 import java.util.HashMap; 8 import java.util.Map; 9 import java.util.Scanner; 10 11 public class 背包 { 12 /* 13 * 非递归回溯*******************

leetcode_401_Binary Watch_回溯法_java实现

题目: A binary watch has 4 LEDs on the top which represent the hours (0-11), and the 6 LEDs on the bottom represent the minutes (0-59). Each LED represents a zero or one, with the least significant bit on the right. For example, the above binary watch

回溯法——n后问题

问题描述: 在n*n的棋盘上放置彼此不受攻击的n个皇后.按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子.n后问题等价于在n*n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线. 盲目的迭代枚举: 1 /* 2 *作者:xymaqingxiang 3 *说明:八皇后--盲目迭代法 4 *分析:通过8重循环模拟搜索空间中的8^8个状态,从中找出满足约束条件的可行性方案 5 *日期:2014-05-15 6 */ 7 #include <iostream>

01背包问题(回溯法)python实现

接上一篇,同样的01背包问题,上一篇采用动态规划的方法,现在用回溯法解决.回溯法采用深度优先策略搜索问题的解,不多说,代码如下: bestV=0 curW=0 curV=0 bestx=None def backtrack(i): global bestV,curW,curV,x,bestx if i>=n: if bestV<curV: bestV=curV bestx=x[:] else: if curW+w[i]<=c: x[i]=True curW+=w[i] curV+=v[i