1. 程式人生 > >0-1揹包問題-分支界限法

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

}