堆砌相同高度的塔

題目

小易有n塊磚塊,每一塊磚塊有一個高度。小易希望利用這些磚塊堆砌兩座相同高度的塔。爲了讓問題簡單,磚塊堆砌就是簡單的高度相加,某一塊磚只能使用在一座塔中一次。小易現在讓能夠堆砌出來的兩座塔的高度儘量高,小易能否完成呢。

  • 輸入描述:
    輸入包括兩行:第一行爲整數n(1 ≤ n ≤ 50),即一共有n塊磚塊,第二行爲n個整數,表示每一塊磚塊的高度height[i] (1 ≤ height[i] ≤ 500000)
  • 輸出描述:
    如果小易能堆砌出兩座高度相同的塔,輸出最高能拼湊的高度,如果不能則輸出-1。保證答案不大於500000。
  • 輸入例子:
    3
    2 3 5
  • 輸出例子:
    5

分析1

不能按照01 揹包問題去解,因爲不能保證堆砌的兩個塔高度相等。磚塊bk for k=0n1 。定義h[i,j] 爲使用前i 塊磚能夠堆砌的低塔高度,j 表示高塔和低塔的高度差。i=0nj=0sum(bk) 這樣定義的好處是可以計算出任意狀態下低塔和高塔各自的高度,且原問題就是h[n,0] 。遞歸式爲

h[i,j]=0,,maxh[i1,j],h[i1,j+bi]+bi,h[i1,bij]+bij,h[i1,jbi],1.i2.i3.i4.i,i,j=0i=0,j0i>0

i=0 時表示還沒有磚塊,高度差j 一定爲0,j0 爲不可能情況。需要比較的四種情況如下圖所示

四種情況

代碼1

import java.util.Scanner;

public class Main {
    static void tower(int[] bricks, int[][] h, int n, int sum) {
        h[0][0] = 0;
        for (int i = 1; i <= sum; i++) {
            h[0][i] = Integer.MIN_VALUE;
        }
        for (int i = 1; i <= n; i++) {
            int b = bricks[i - 1];
            for (int j = 0; j <= sum; j++) {
                h[i][j] = h[i - 1][j];
                if (j + b <= sum) {
                    h[i][j] = Math.max(h[i][j], h[i - 1][j + b] + b);
                }
                if (b - j >= 0) {
                    h[i][j] = Math.max(h[i][j], h[i - 1][b - j] + b - j);
                } else {
                    h[i][j] = Math.max(h[i][j], h[i - 1][j - b]);
                }
            }
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] bricks = new int[n];
        int sum = 0;
        for (int i = 0; i < n; i++) {
            bricks[i] = sc.nextInt();
            sum = sum + bricks[i];
        }
        int[][] h = new int[n + 1][sum + 1];
        tower(bricks, h, n, sum);
        System.out.println(h[n][0] > 0 ? h[n][0] : -1);
    }
}

分析2

另一種簡單的解法是定義h[i,j] 爲使用前i 塊磚能夠堆砌的一個塔的高度,j 表示它和另外一個的高度差。這就會導致j 會有負值出現。爲此需要將j 的取值擴展一倍即j=02sum(bk) ,原問題爲h[n,sum(bk)] 。則遞歸式爲

h[i,j]=0,,maxh[i1,j],h[i1,jbi],h[i1,j+bi]+bi,1.i2.i3.i,i=0,j=sum(bk)i=0,jsum(bk)i>0

代碼2

import java.util.Scanner;

public class Main {
    static void tower(int[] bricks, int[][] h, int n, int sum) {
        for (int i = 0; i < 2 * sum + 1; i++) {
            h[0][i] = Integer.MIN_VALUE;
        }
        h[0][sum] = 0;
        for (int i = 1; i <= n; i++) {
            int b = bricks[i - 1];
            for (int j = 0; j < 2 * sum + 1; j++) {
                h[i][j] = h[i - 1][j];
                if (j - b >= 0) {
                    h[i][j] = Math.max(h[i][j], h[i - 1][j - b]);
                }
                if (j + b < 2 * sum + 1) {
                    h[i][j] = Math.max(h[i][j], h[i - 1][j + b] + b);
                }
            }
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] bricks = new int[n];
        int sum = 0;
        for (int i = 0; i < n; i++) {
            bricks[i] = sc.nextInt();
            sum = sum + bricks[i];
        }
        int[][] h = new int[n + 1][2 * sum + 1];
        tower(bricks, h, n, sum);
        System.out.println(h[n][sum] > 0 ? h[n][sum] : -1);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章