回溯法最優裝載問題(java)


1.問題描述:
     有一批共有 n 個集裝箱要裝上兩艘載重量分別為 c1 和 c2 的輪船,其中集裝箱 i 的重量為 w[i], 且重量之和小於(c1 + c2)。裝載問題要求確定是否存在一個合理的裝載方案可將這 n 個集裝箱裝上這兩艘輪船。如果有,找出一種裝載方案。
    例如,當n=3,c1=c2=50,且w=[10,40,40]時,可將集裝箱1和集裝箱2裝上一艘輪船,而將集裝箱3裝在第二艘輪船;如果w=[20,40,40],則無法將這3個集裝箱都裝上輪船。
容易證明,如果一個給定的裝載問題有解,則采用如下的策略可以得到最優裝載方案。
   1.首先將第一艘輪船盡可能裝滿。
   2.將剩余的集裝箱裝上第二艘輪船。
   將第一艘輪船盡可能的裝滿等價於選取全體集裝箱的子集,使該子集中集裝箱的重量之和最接近 c1 。因此,等價於一個特殊的 0-1 背包問題。 因此是一棵子集樹。
    max(w1x1+w2x2+...+wixi) 
   (w1x1+w2x2+...+wixi)<= c1;
    xi @{0,1},1<=i<=n
   2 算法設計  
   用回溯法解裝載問題時,用子集樹表示其解空間顯然是最合適的。可行性約束函數可剪去不滿足約束條件(

   (w1x1+w2x2+...+wixi)<= c1)的子樹。在子集樹的第j+1層的節點Z處,用cw記當前的裝載重量,即cw=(w1x1+w2x2+...+wjxj),當cw>c1時,以節點Z為根的子樹中所有節點都不滿足約束條件,因而該子樹中解均為不可行解,故可將該子樹剪去。

package cn.cb.offer.backtrack;

import javax.swing.*;
import java.util.Scanner;

/**
 * Created by IntelliJ IDEA.
 * User: duanxx
 * email:duanxx@staff.chinabyte.com
 * Date: 13-10-16
 * Time: 下午2:45
 * 最優裝載問題回溯法
 */
public class Loading {
    private int n;//集裝箱數
    private int[] w;//集裝箱重量數組
    private int c;//第一艘輪船的載重量
    private int cw;//當前載重量
    private int bestw;//當前最優載重量
    private int r;//剩余集裝箱重量
    private int[] x;//當前解
    private int[] bestx;//當前最優解

    /**
     *
     * @param i
     */
    public void backtrace(int i) {
        //1.到達葉節點
        if (i > n-1) {   //i此時的值=葉節點+1
            if (cw > bestw) {
                for (int j = 0; j < n; j++) {
                    bestx[j] = x[j];
                    bestw = cw;
                }
                return;
            }
        }
        r -= w[i];
        //2.搜索左子樹
        if (cw + w[i] < c) {   //x[i =1
            x[i] = 1;
            cw += w[i];
            backtrace(i + 1);
            cw -= w[i];
        }
        //3.搜索右子樹
        if (cw + r > bestw) {
            x[i] = 0;
            backtrace(i + 1);
        }
        r += w[i];
    }

    public static void main(String[] args) {
        Loading X = new Loading();
        /*String s1 = JOptionPane.showInputDialog(null, "輸入貨物數量:",
                "最優裝載問題", JOptionPane.QUESTION_MESSAGE);*/
        Scanner scanner = new Scanner(System.in);
        String s1 = scanner.nextLine();
        X.n = Integer.parseInt(s1);
        X.w = new int[X.n];
        X.x = new int[X.n];
        X.bestx= new int[X.n];
        System.out.println("輸出貨物的重量數組:");
        for (int i = 0; i < X.n; i++) {
            X.w[i] = (int) (100 * Math.random());
            System.out.println(X.w[i]);
        }
        /*String s2 = JOptionPane.showInputDialog(null, "輸入第一艘輪船的載重量:",
                "最優裝載問題", JOptionPane.QUESTION_MESSAGE);*/

        String s2 = scanner.nextLine();
        X.c = Integer.parseInt(s2);

        for (int i = 0; i < X.n; i++)
            X.r += X.w[i];
        X.backtrace(0);
        System.out.print("輸出當前最優解:");
        for (int i = 0; i < X.n; i++) System.out.print(X.bestx[i] + " ");
        System.out.println();
        System.out.println("最優解:" + X.bestw);
    }


}



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM