回溯算法类似于遍历的求解,但不同于无脑遍历的的地方是它在每一步都判断是否满足约束条件,及回溯点,所以可以理解为有条件的遍历。使用回溯算法求解01背包最优解时需要建立二叉树,树有业务意义的深度为物品数量n,加上根节点总深度为n+1,除了终端节点外,每个叶子节点都有左右两个children节点,left children定义为装入当前物品的情况,right children为不装入当前物品的情况,节点拥有“剩余最大容量”和“当前价值”两个属性,回溯点就是当剩余最大容量无法装入当前物品,或当前物品已是终端节点。

package test;

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

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

    private List<Node> nodeList=new ArrayList<>();

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

    /**
     * 回溯算法
     */
    public void backtracking(){
        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));
        //【1】定义二叉树的节点,包括左右子节点、剩余空间、当前总价值
        //【2】起始根节点
        Node root=new Node();
        root.setSurplusV(rucksackV);
        root.setWorth(0);
        Node parentNode=root;
        again(goodsList, parentNode, 0);
        int maxV=0;
        for (Node node:nodeList){
            System.out.print(node.getWorth()+",");
            if (maxV<node.getWorth()){
                maxV=node.getWorth();
            }
        }
        System.out.println();
        System.out.println(maxV);
    }

    private void again(List<Goods> goodsList, Node parentNode, int i) {
        if (i>=goodsList.size()){
            nodeList.add(parentNode);
            return;
        }
        Goods g=goodsList.get(i);
        //【1】左节点
        int surplus=parentNode.getSurplusV()-g.getVolume();
        if (surplus>=0){
            Node leftNode=new Node();
            leftNode.setSurplusV(surplus);
            leftNode.setWorth(parentNode.getWorth()+g.getWorth());
            parentNode.setLeftNode(leftNode);
            again(goodsList, leftNode, i+1);
        }
        //【2】右节点,右节点复制父节点数据
        Node rightNode=new Node();
        rightNode.setSurplusV(parentNode.getSurplusV());
        rightNode.setWorth(parentNode.getWorth());
        parentNode.setRightNode(rightNode);
        again(goodsList, rightNode, i+1);
    }
}

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 Node leftNode;
    private Node rightNode;

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

    public Node getLeftNode() {
        return leftNode;
    }

    public void setLeftNode(Node leftNode) {
        this.leftNode = leftNode;
    }

    public Node getRightNode() {
        return rightNode;
    }

    public void setRightNode(Node rightNode) {
        this.rightNode = rightNode;
    }
}