回溯法-----装载问题(java代码详解)

1、代码

public class XLoading {
    static int c;//船的载重量
    static int n;//物品数量
    static int[] w;//物品的重量
    static int cw;//当前船的载重量
    static int bestw;//当前最优载重量(最大载重量)
    static int r;//剩余物品重量-----未考察过的物品的重量,并非没有装载的物品的重量,所以考察到就减去

    static int[] X;//是否装载当前深度的物品,装载则X[i]=1,不装载则X[i]=0
    static int[] Xbest;//记录最优解,最优路径

    public static void main(String[] args) {
        int w[] = {0, 20, 30, 60, 40, 40};
        int c = 100;
        int n = w.length - 1;
        System.out.print("货物重量为: ");
        for (int i = 1; i <= n; i++) {
            System.out.print(w[i] + "  ");
        }
        System.out.println();
        System.out.println("第一艘船载重量为: " + c);
        System.out.println("第二艘船载重量为: " + c);

        Initialize(w, c);
        int weight2 = 0;
        for (int i = 1; i <= n; i++) {
            weight2 += w[i] * (1 - Xbest[i]);
        }
        if (weight2 > c)
            System.out.println("无解!");
        else {
            System.out.println("第一艘船的货物载重为: " + bestw);
            System.out.println("第二艘船的货物载重为: " + weight2);
            for (int i = 1; i <= n; i++) {
                if (Xbest[i] == 1)
                    System.out.println("第" + i + "件物品装入第一艘船");
            }
            for (int i = 1; i <= n; i++) {
                if (Xbest[i] == 0)
                    System.out.println("第" + i + "件物品载入第二艘船");
            }
        }
    }

    public static int Initialize(int[] weight, int capacity) {
        n = weight.length - 1;
        w = weight;
        c = capacity;
        bestw = 0;
        cw = 0;
        r = 0;
        X = new int[n + 1];//注意不要X[] = new int[n+1] ,X那里不需要[],因为开头已经定义
        Xbest = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            r = r + w[i];
        }//记录最大剩余物品重量,也就是总重量
        Backtrack(1);
        return bestw;
    }

    public static void Backtrack(int i) {
        if (i > n) {//i>n,表示已经到叶子节点
            if (cw > bestw) {
                for (int j = 1; j <= n; j++)
                    Xbest[j] = X[j];//记录最优路径
            }
            bestw = cw;//若cw>bestw,更新bestw=cw
            return;
        }
        r = r - w[i];//计算剩余(未考察)的物品的重量,减去当前考察过的对象的重量
        //剪枝函数
        if (cw + w[i] <= c) {//约束函数
            cw = cw + w[i];//进入子树,则+
            X[i] = 1;//左子树1,右子树0
            Backtrack(i + 1);
            cw = cw - w[i];//到这来表示已经从Backtrack(i+1)里出来,则要复原cw,所以前面+,这里则-,恢复原状。
        }
        if (cw + r > bestw) {//限界函数,如果cw+r不大于bestw,则不用进入下一层了,因为进入也不大于bestw
            //这里不用约束函数,因为不取X[i]=0则一定不会大于c
            //因为r值是累计的(在Backtrack(i+1)里),所以已经减了r=r-w[i]已经减去了w[i],
            // 当你退出Backtrack(i+1)后,返回上一层回溯,就得恢复r,所以有r=r+w[i]
            X[i] = 0;
            Backtrack(i + 1);
        }
        r = r + w[i];//递归回退返回上一层时,记得修改r的当前值,如果得不到最优解,
        // 再取消当前考察的集装箱,标记为未选,因此剩余容量要再加上当前集装箱重量
    }
}


2、结果

回溯法-----装载问题(java代码详解)_第1张图片

3、先r=r-w[i],后r=r+w[i]的原因

回溯法-----装载问题(java代码详解)_第2张图片

你可能感兴趣的:(回溯法-----装载问题(java代码详解))