小易有n塊磚塊,每一塊磚塊有一個高度。小易希望利用這些磚塊堆砌兩座相同高度的塔。爲了讓問題簡單,磚塊堆砌就是簡單的高度相加,某一塊磚只能使用在一座塔中一次。小易現在讓能夠堆砌出來的兩座塔的高度儘量高,小易能否完成呢。
輸入描述:
輸入包括兩行:
第一行爲整數n(1 ≤ n ≤ 50),即一共有n塊磚塊
第二行爲n個整數,表示每一塊磚塊的高度height[i] (1 ≤ height[i] ≤ 500000)
輸出描述:
如果小易能堆砌出兩座高度相同的塔,輸出最高能拼湊的高度,如果不能則輸出-1.
保證答案不大於500000。
示例1
輸入
3
2 3 5
輸出
5
解題思路
動態規劃
假設磚塊分爲A,B兩堆,dp[i][j]中的j表示B-A的長度。
因爲B-A有可能是負的,所以j整體偏移sum個長度,即2*sum+1。
而dp[i][j]的值則表示當A-B的值爲j時,B的最大長度是多少。
dp[i][j] = dp[i-1][j]表示我不用第i塊磚
dp[i][j] = max(dp[i-1][j-h], dp[i-1][j])表示把磚放在A堆。
dp[i][j] = max(dp[i-1][j+h]+h, dp[i-1][j])表示把磚放在B堆。
因爲會爆內存,所以用了滾動數組。下一次結果只依賴於前一次,因而只保存前一次狀態和當前狀態即可。
import java.util.Scanner;
public class Main {
private static int fun(int[] data) {
int length = data.length;
int sum = 0;
for (int num : data)
sum += num;
int[] dp0 = new int[2 * sum + 1];
int[] dp1 = new int[2 * sum + 1];
for (int i = 0; i < dp0.length; i++)
dp0[i] = -1;
dp0[sum] = 0;
for (int i = 0; i < length; i++) {
int h = data[i];
for (int j = 0; j < 2 * sum + 1; j++) {
dp1[j] = dp0[j];
if (j - h >= 0 && dp0[j - h] != -1) {
dp1[j] = Math.max(dp0[j - h], dp1[j]);
}
if (j + h <= 2 * sum && dp0[j + h] != -1) {
dp1[j] = Math.max(dp0[j + h] + h, dp1[j]);
}
}
int[] temp = dp0;
dp0 = dp1;
dp1 = temp;
}
return dp0[sum] == 0 ? -1 : dp0[sum];
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] data = new int[n];
for (int i = 0; i < n; i++)
data[i] = sc.nextInt();
System.out.println(fun(data));
}
}