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

上文已讲述了回溯法以及01背包问题的原理,本文讲述如何顺序执行解决01背包问题以及通过模板模式重构软件。

一、顺序执行流程图

图1无剪枝函数的01背包问题顺序执行算法流程图

图2 有剪枝函数的01背包问题顺序执行算法流程图

无剪枝函数是通用的深度遍历算法,为了减少搜索深度可通过剪枝函数处理完全不可能的分枝。与递归方案的区别主要表现在i>=n后需要“回溯”,即用后进先出的方式将物品逐个拿出。

二、执行代码

递归与顺序执行方法仅仅是实现方法Backtracking(int i)不同,其余的完全一致,因此可将具体实现延迟至子类中。模板方法使得自雷可以改变一个算法的结构即可重定义该算法的某些特定步骤,因此采用模板模式。类图结构如图3所示:

图3 回溯法模板模式类图

代码1 测试代码

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 };

            AbsBacktracking r = new Backtracking_Nonrecursion();

            r.W = 10;
            r.objs = objs;
            Console.WriteLine("Nonrecursion Model:");
            r.Backtracking(0);

            Console.WriteLine("Recursion Model:");
            r = new Backtracking_Recursion();
            r.W = 10;
            r.objs = objs;
            r.Backtracking(0);

            Console.Read();
		}

代码2 抽象类 AbsBacktracking

public abstract class AbsBacktracking
    {
        #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 abstract void Backtracking(int i);

        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());
        }
    }

代码3 类Backtracking_Nonrecursion

public class Backtracking_Nonrecursion:AbsBacktracking
    {

        public override void Backtracking(int i)
        {
            while (true)
            {
                if (i < n)
                {
                    if (m_currentWeight + objs[i].Weight <= W)
                    {
                        //将第i个物品放入包中
                        m_currentWeight += objs[i].Weight;
                        m_currentPrice += objs[i].Price;
                        objs[i].Selected = true;
                    }
                }
                else
                {
                    //打印路径
                    Printing();
                    i--;
                    while (i >= 0 && !objs[i].Selected)
                    {
                        i--;
                    }

                    if (i < 0)
                    {
                        return;
                    }
                    else
                    {
                        //将i从包内拿出
                        m_currentWeight -= objs[i].Weight;
                        m_currentPrice -= objs[i].Price;
                        objs[i].Selected = false;

                    }

                }
                i++;
            }

        }

    }

代码4 代码片段Backtracking_Recursion

public class Backtracking_Recursion :AbsBacktracking
	{
		public override 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);
		}

	}

代码5 Obj代码片段

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

三、运行结果:

注:上述实现中没有添加剪枝函数功能,也没有添加判断最优路径功能,读者可继续优化。

下载源代码

回溯法-01背包问题之二:顺序执行模式,布布扣,bubuko.com

时间: 2024-10-06 00:52:33

回溯法-01背包问题之二:顺序执行模式的相关文章

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

一.回溯法 回溯法是一个既带有系统性又带有跳跃性的搜索算法.它在包含问题的所有解的解空间树中按照深度优先的策略,从根节点出发搜索解空间树.算法搜索至解空间树的任一节点时,总是先判断该节点是否肯定不包含问题的解.如果肯定不包含,则跳过对以该节点为根的子树的系统搜索,逐层向其原先节点回溯.否则,进入该子树,继续按深度优先的策略进行搜索. 运用回溯法解题通常包含以下三个步骤: · 针对所给问题,定义问题的解空间: · 确定易于搜索的解空间结构: · 以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函

回溯法--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=

回溯法解背包问题分析

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

python之fabric(二):执行模式(转)

执行模式 执行模式可以让你在多个主机上执行多个任务. 执行策略: 默认fabric是单个有序地执行方法,其行为如下: 1. 创建一系列任务,通过fab任务执行要执行的任务: 2. 根据主机列表定义,去执行每一个任务: 3. 没有主机定义的任务,将在本地执行一次. 如: from fabric.api import run, env env.hosts = ['host1', 'host2'] def taskA(): run('ls') def taskB(): run('whoami') #

回溯法~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 * 非递归回溯*******************

0-1背包问题的动态规划法与回溯法

一.动态规划 状态转移方程: 1 从前往后: 2 if(j>=w[i]) 3 m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+v[i]); 4 else 5 m[i][j]=m[i-1][j]; 6 7 从后往前: 8 if(j>=w[i]) 9 m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]); 10 else 11 m[i][j]=m[i+1][j]; 算法: 1 从前往后: 2 for(int i=1;i<=n;i++)

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

回溯法——求解0-1背包问题

以前研究过一个简单的N皇后问题,对回溯法也有了个模糊的认识,大致理解就是:先一直做某件事,当完成某个条件时或者是触犯某个条件时,再返回到最近的一个类似还原点的地方. 在用回溯法求解0-1背包问题的时候,主要遇到三个相对难解决的问题:1,什么是界限函数:2,什么时候用它:3,回溯到哪儿. 什么是界限函数? 如下图: 当我们身在一棵搜索空间树中,站在一个K点举棋不定的时候,我们可以用它估算如果我们继续向下走,我们走完本段路会获得的总价值.假设我们现在有一个最大解,当我用界限函数算出一个价值后和我当前