算法學習——動態規劃之裝載問題

算法描述

兩艘船各自可裝載重量爲c1,c2,n個集裝箱,各自的重量爲w[n],設計一個能夠裝載的方案,使得兩艘船裝下所有集裝箱算法

算法思路

  1. 將第一艘船儘可能裝滿(第一艘船放的集裝箱的重量之和接近c1),剩餘的集裝箱放入第二艘船,若剩餘的集裝箱重量之和大於第二艘船,則無解數組

  2. 定義一個一維數組,a[n] 存放對應的集裝箱的重量設計

  3. 定義一個數組,m[i][j]表示第一艘船還可裝載的重量j,可取集裝箱編號範圍爲i,i+1...n的最大裝載重量值code

    例如 如今有3個集裝箱 重量分別爲9,5,3,即a[1]=9 a[2]=5 a[3]=3blog

    m[1][2]=0 可裝載重量爲2,此時上述的三個集裝箱都不能裝入,因此爲最大可裝載重量爲0程序

    m[1][3]=m[1][4]=3 可裝載重量爲3或者是4的時候,都是隻能裝入重量爲3的那個集裝箱,因此最大可裝載重量爲3 `im

    實際上,這裏的3=a[3]+m[1][2],是一個遞推的關係,具體看下面`統計

  4. m[i][j]分下面兩種狀況
    • 0<=j<a[n] (當可裝載重量j小於第n個集裝箱的重量w[n],此時就不能往船上裝此集裝箱) m[i][j] = m[i+1][j]next

    • j>=a[n]可裝載重量j大於或等於第n個集裝箱的重量w[n]),此時剩餘的可裝載重量爲j-a[n](裝入了此時的集裝箱),最大的可裝載重量爲m[i+1][j-w[n]]+w[n]db

      可是咱們是須要最大的可裝載重量,因此得與若是不將當前集裝箱裝入的那種狀況m[i+1][j]進行比較

      m[i][j]=Math.max(m[i+1][j],m[i+1][j-a[n]+a[n]])

  5. 上面咱們就得到了一個關於m[i][j]的遞推關係,咱們經過逆推得到所有的數值

    • 初始值

      m[i][j]=0 這裏的i=n j從0到a[n] 這裏的a[n]是第n個集裝箱重量(最後一個集裝箱的重量)

      這裏的賦值其實就是上述m[i][j]兩種狀況的第一種狀況,最後一個集裝箱的重量大於可裝載重量,不裝載此集裝箱,因此最大可裝載重量爲0,

      m[i][j]=a[n] 這裏的i=n j從a[n]到c1 這裏的a[n]是第n個集裝箱的重量(最後一個集裝箱的重量)

      這裏的意思爲當可裝載重量j只要都是大於最後一個集裝箱的重量a[n],便可裝入此集裝箱,因此最大可裝載重量等於裝入的集裝箱的重量

    • 開始逆推

      使用上述的遞推公式進行逆推

      for (int i = n; i >= 1 ; i--) {
            for (int j = 1; j <=c1; j++) {
                if(j>=a[i]){
                    m[i][j] = Math.max(m[i+1][j],m[i+1][j-a[i]]+a[i]);
                }else{
                    m[i][j]=m[i+1][j];
                }
            }
        }
  6. 以後再進行輸出,輸出第一艘船的裝載方案,輸出第二艘船的裝載方案

算法實現

System.out.println("輸入第一艘船可裝載重量c1:");
    Scanner scanner = new Scanner(System.in);
    int c1 = scanner.nextInt();
    System.out.println("輸入第二艘船可裝載重量c2:");
    int c2 = scanner.nextInt();
    System.out.println("輸入集裝箱個數n:");
    int n = scanner.nextInt();

    int[] a = new int[n+1];
    //使用一維數組存放集裝箱重量
    System.out.println("依次輸入集裝箱的重量");
    for (int i =1; i < n+1; i++) {
        a[i] = scanner.nextInt();
    }


    int sum = 0;//集裝箱重量總和
    for (int i = 0; i < a.length; i++) {
        sum=sum+a[i];
    }
    //超重狀況
    if(sum>c1+c2){
        System.out.println("集裝箱重量之和大於兩艘船可裝載重量,題目無解");
        return;//結束程序
    }

    int[][] m = new int[100][100];//m[i][j]表示第一艘船還可裝載的重量j,可取集裝箱編號範圍爲i,i+1...n的最大裝載重量值
    //賦初始值,因爲是逆推,因此從末尾開始
    //可裝載重量j小於第n個集裝箱重量a[n],不裝此集裝箱,賦值爲0
    for (int j = 0; j < a[n]; j++) {
        m[n][j] = 0;
    }
    //可裝載重量j大於或等於第n個集裝箱重量a[n],裝載此集裝箱,此時刻最大裝載重量值爲a[n]
    for (int j = a[n]; j <=c1 ; j++) {
        m[n][j]=a[n];
    }

    //關鍵逆推代碼
    for (int i = n; i >= 1 ; i--) {
        for (int j = 1; j <=c1; j++) {
            if(j>=a[i]){
                m[i][j] = Math.max(m[i+1][j],m[i+1][j-a[i]]+a[i]);
            }else{
                m[i][j]=m[i+1][j];
            }
        }
    }
    int maxc1 = m[1][c1];//最大可裝載重量
    System.out.println("maxc1="+maxc1);

    if(maxc1>sum-c2){
        int cw = m[1][maxc1];
        int sw,i;
        //輸出第一艘船的裝載
        System.out.println("第一艘船裝載:");
        for (sw=0,i=1;i<=n;i++){
            if(m[i][cw]>m[i+1][cw]){

                cw = cw-a[i];
                sw=sw+a[i];//統計sw,sw的最終結果與maxc1相等
                System.out.print(a[i]+"     ");

                a[i]=0;//裝載當前的集裝箱
            }
        }
        System.out.print("("+sw+")");
        System.out.println("");
        //輸出第二艘船的裝載
        System.out.println("第二艘船裝載:");
        for(sw=0,i=1;i<=n;i++){
            //已裝載在第一艘船的集裝箱a[i]都已經爲0了,只須要將不爲0的那些集裝箱裝入第二艘船便可
            if(a[i]!=0){
                System.out.print(a[i]+"     ");
                sw=a[i]+sw;
            }
        }
        System.out.println("("+sw+")");

    }else{
        System.out.println("無解");
    }

結果

相關文章
相關標籤/搜索