• 回溯求解0-1背包


    回溯法本质上是一种深度优先搜索状态空间树的算法。

     

    假设不引入剪枝函数(约束函数+限界函数)。则是穷举算法。

     

    引入适当的限界函数,剪去已能确信不含最优答案结点的子树,使其成为一种启示式算法。

     

    显示约束:xi=1表示将第i件物品装入背包, xi=0表示第i件物品不装入背包。
    隐式约束:

     kk


    解空间大小为2n 

    解空间树为高度为n+1的满二叉树。

     

    下界函数:变量L初值为0,遇到一个答案结点便计算该答案结点的收益值fp,且令L=max{L,fp}。则L中始终保存迄今为止已经搜索到的答案结点中收益的最大值。0/1背包的最优解值必然大于等于L,因此最优解值的下界预计值为L

     

    限界函数:状态空间树中任一结点X,若其上界函数值bp<最优解值的下界预计值变量L。则可断定X子树上不含最优答案结点。能够剪去以X为根的子树。
    剪去不含最优解的分枝【怎么都小于已经搜索到的答案节点收益最大值】

     

    上界函数:当前位于状态空间树的结点X处,cw为背包当前重量。cp为当前已装入背包物品的总收益。则贪心法求解剩余载重和剩余物品构成的一般背包问题(物品编号k+1,k+2,...,n-1,载重M-cw)最大收益为rp则以X为根的子树上全部可能答案结点的目标函数值                     不可能超过bp=cp+rp。因此结点X的上界函数值为bp

     

    8-4  设有0/1背包n=8, M=110(w0,w1,...,w7)=(1,11,21,23,33,43,45,55),
    (p0,p1,...,p7)=(11,21,31,33,43,53,55,65)
    ——按pi/wi非增排列,即pi/wipi+1/wi+1


    ffkk

    lljj


    kk


    总结:向左走减去不可行的解的分支【不满足隐形约束的】 向右走减去不含最优解的【就是不管怎样小于L的】


    以下给出我的Java代码


    public class Packet {
    	
    	public int []w;
    	
    	private int m;
    	
    	private int n;
    	
    	public int []p;
    	
    	public int fp;
    	
    	
    	public Packet()
    	{
    		w=new int[]{30,10,20,50,40};
    		p=new int[]{65,20,30,60,40};
    	}
    	public static void main(String args[])
    	{
    		Scanner input=new Scanner(System.in);
    		Packet p=new Packet();
    		int []x=new int [5];
    		int []y=new int [5];
    		p.m=100;
    		p.n=5;
    		p.BKnapsack(0, 0, 0, x, y);
    		for(int i=0;i<5;i++)
    		{
    			System.out.println(x[i]);
    		}
    	}
    
    	public int Bound(int k,int cp,int cw)
    	{
    		int b = cp, c = cw; // 当前收益cp和当前背包重量cw不变(xk=0)
    		for (int i = k + 1; i < n; i++) // 对剩余物品求一般背包问题的解
    		{
    			c += w[i];
    			if (c < m)
    				b += p[i]; // 第i个物品能够所有放入
    			else
    				return b ;
    		}
    		return b;
    
    	}
    	
    	
    	public void BKnapsack(int k,int cp,int cw,int []x,int []y)
    	{
    		if (cw+w[k]<=m)	//左子树,需又一次计算约束函数,上界函数无需计算
    		   {
    			y[k]=1;
    			if (k<n-1) 		
    			{
    				BKnapsack(k+1,cp+p[k],cw+w[k],x,y);
    			}
    			if (cp+p[k]>fp && k==n-1)	//到最底层
    			{	fp=cp+p[k];		//更新最优解下界预计值
    				for (int j=0;j<=k;j++) x[j]=y[j];
    			}
    		   }
    		 if (Bound(k,cp,cw)>=fp) //右子树,需又一次计算上界函数。约束函数无需计算
    		   {
    			y[k]=0;
    			if (k<n-1) 		//未究竟
    				BKnapsack(k+1,cp,cw,x,y);	
    			if (cp>fp && k==n-1)	//到最底层
    			{	fp=cp;		//更新最优解下界预计值
    				for (int j=0;j<=k;j++) x[j]=y[j];
    			}
    		   }
    	}
    
    
    }


  • 相关阅读:
    Leetcode 121. Best Time to Buy and Sell Stock
    Leetcode 120. Triangle
    Leetcode 26. Remove Duplicates from Sorted Array
    Leetcode 767. Reorganize String
    Leetcode 6. ZigZag Conversion
    KMP HDU 1686 Oulipo
    多重背包 HDU 2844 Coins
    Line belt 三分嵌套
    三分板子 zoj 3203
    二分板子 poj 3122 pie
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/7136210.html
Copyright © 2020-2023  润新知