0-1背包问题-分支界限法

        分支界限法和回溯法很像,不同之处是回溯法使用深度优先搜索,而分支界限法使用的是广度优先搜索,并使用了队列来记录每次有有效结点,通过入队出队的方式遍历有效结点。分支界限法在从活结点选择下一扩展结点时的不同方法导致不同分支界限法,常见的有队列分支界限法和优先队列分支界限法,这里以队里分支界限法为例。

        下边的代码设计有部分比较难理解,这里做个特别说明:使用分支界限法解01背包时,因为同层结点的子结点其实都是同一个物品的“装”与“不装”两个状态,所以通过记录结点的深度(即物资的位置)构建了虚拟的树(这里只的虚拟树是指每个结点并没有保存和父结点或子结点的关系,所以无法通过指针或是java里的属性值遍历树)。这种设计方式避免了构建树的过程,可以直接通过逻辑判断遍历虚拟树。

package test;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by saishangmingzhu on 2018/11/26.
 */
public class Rucksack {

    //【1】输入背包容量
    //【2】输入物品体积及价值
    public static void main(String[] arg) {
        new Rucksack().branchAndBoundMethod();
    }

    /**
     * 分支界限法-队列式
     */
    public void branchAndBoundMethod() {
        int rucksackV=10;
        List<Goods> goodsList=new ArrayList<>();
        goodsList.add(new Goods("书",1,2));
        goodsList.add(new Goods("足球",3,4));
        goodsList.add(new Goods("大箱子",7,2));
        goodsList.add(new Goods("macbook",3,6));
        goodsList.add(new Goods("iphone",1,5));
        goodsList.add(new Goods("礼盒",5,3));
        goodsList.add(new Goods("小箱子",4,2));
        int goodsListSize=goodsList.size();
        //【1】定义二叉树的结点,包括左右子结点、剩余空间、当前总价值
        //【2】起始根结点
        Node root=new Node();
        root.setSurplusV(rucksackV);
        root.setWorth(0);
        root.setLevel(0);
        Node parentNode=root;
        //【3】定义队列
        List<Node> queueNodeList=new ArrayList<>();
        List<Node> queueLeafNodeList=new ArrayList<>();
        queueNodeList.add(parentNode);
        while (queueNodeList.size()>0){
            parentNode=queueNodeList.get(0);
            System.out.println("("+parentNode.getWorth()+","+parentNode.getSurplusV()+")");
            int nextLevel=parentNode.getLevel()+1;
            if (nextLevel>goodsListSize){
                queueLeafNodeList.add(parentNode);
            } else {
                Goods g = goodsList.get(parentNode.getLevel());
                int surplus = parentNode.getSurplusV() - g.getVolume();
                if (surplus >= 0) {
                    Node node = new Node();
                    node.setLevel(nextLevel);
                    node.setSurplusV(surplus);
                    node.setWorth(parentNode.getWorth() + g.getWorth());
                    queueNodeList.add(node);
                }
                Node node = new Node();
                node.setLevel(nextLevel);
                node.setSurplusV(parentNode.getSurplusV());
                node.setWorth(parentNode.getWorth());
                queueNodeList.add(node);
            }
            queueNodeList.remove(0);
        }
        int maxV=0;
        for (Node node:queueLeafNodeList){
            System.out.print(node.getWorth()+",");
            if (maxV<node.getWorth()){
                maxV=node.getWorth();
            }
        }
        System.out.println();
        System.out.println(maxV);
    }
}

class Goods{
    private String name;
    private int volume;
    private int worth;

    public Goods(){}
    public Goods(String n,int v,int w){
        this.name=n;
        this.volume=v;
        this.worth=w;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getVolume() {
        return volume;
    }

    public void setVolume(int volume) {
        this.volume = volume;
    }

    public int getWorth() {
        return worth;
    }

    public void setWorth(int worth) {
        this.worth = worth;
    }
}

class Node{
    private int surplusV;
    private int worth;
    private int level;

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public int getSurplusV() {
        return surplusV;
    }

    public void setSurplusV(int surplusV) {
        this.surplusV = surplusV;
    }

    public int getWorth() {
        return worth;
    }

    public void setWorth(int worth) {
        this.worth = worth;
    }

}


猜你喜欢

转载自blog.51cto.com/zuohao1990/2324050