回溯法 01背包问题 剪枝

来源:互联网 发布:真正的男人 知乎 编辑:程序博客网 时间:2024/06/05 12:49

背包问题涉及的是子集树,层数即物品的数量,
每个物品有选和不选两种选择,即每个节点有左子树(选)和右子树(不选)
而恰当的剪枝函数体现在对待右子树上,
因为右子树至少是不选1个了,因此很有可能出现以下情况:
剩下的所有物品价值加起来还没有目前为止的maxvalue大
当这种情况出现时,就可以剪枝了,避免不必要的查找。

package niuke;/** * Created by asus on 2017/11/29. */public class Bags01 {    int n = 5;    int capacity = 10;    int[] weight = {2,6,4,1,5};    double[] value = {6,9,6,1,4};    int maxValue = 0;    int tempValue;    int tempWeight;    int[] way = new int[n];    int[] bestWay = new int[n];    public void backTrack(int t){        //已经搜索到根节点        if(t>n-1){            if(tempValue > maxValue){                maxValue = tempValue;                for(int i=0;i<n;i++)                    bestWay[i] = way[i];            }            return;        }        //搜索左边节点        if(tempWeight + weight[t] <= capacity){            tempWeight += weight[t];            tempValue += value[t];            way[t] = 1;            backTrack(t+1);            tempWeight -= weight[t];            tempValue -= value[t];            way[t] = 0;        }        //不装入这个物品,直接搜索右边的节点        if( bound(t+1) >= maxValue){            backTrack(t+1);        }    }    //用于计算剩余物品的最高价值上界    public double bound(int k){        double maxLeft = tempValue;        int leftWeight = capacity - tempWeight;        //尽力依照单位重量价值次序装剩余的物品        while(k <= n-1 && leftWeight > weight[k] ){            leftWeight -= weight[k];            maxLeft += value[k];            k++;        }        //不能装时,即leftWeight < weight[k],但此时并不能确保该物品之后就没有可选的了        // 用下一个物品的单位重量价值折算到剩余空间作为推测。        if( k <= n-1){            maxLeft += value[k]/weight[k]*leftWeight;        }        return maxLeft;    }    public static void main(String[] args){        Bags01 b = new Bags01();        b.backTrack(0);        System.out.println("该背包能够取到的最大价值为:"+b.maxValue);        System.out.println("取出的方法为:");        for(int i : b.bestWay)            System.out.print(i+"  ");    }}//output/*该背包能够取到的最大价值为:16取出的方法为:1  1  0  1  0  */
原创粉丝点击