题目描述
小明很喜欢摆积木,现在他正在玩的积木是由N个木块组成的,他想用这些木块搭出两座高度相同的塔,一座塔的高度是搭建它的所有木块的高度和,并且一座塔至少要用一个木块。每个木块只能用一次,也可以不用。目前已知每块木块的高度,小明想知道在最终两个塔的高度相同的情况下,他所能搭的塔的最大高度是多少,你能帮助他吗?
输入输出格式
输入格式:
第一行为一个整数N,表示木块个数。
第二行是N个整数,表示N块木块的高度。
【数据规模】
对于100%的数据,N≤50,每块木块的高度h满足1≤h≤500000,所有木块的高度总和≤500000。
输出格式:
仅一个整数,表示能搭建的塔的最大高度,若不能搭建两座相同高度的塔,则输出“-1”。
输入输出样例
输入样例#1:
3
2 3 5
输出样例#1:
5
思路:
这道题我们可以设dp[i][j]
代表用前i个木块拼出的塔相差j时的较低塔的高度,初始化dp[1][a[1]]=0;(使用第一个木块) dp[1][0]=0;(不使用第一个木块)
,其余初始化为-1,这样这道题会有4种情况:
1.当不使用第i个木块:dp[i][j] = dp[i - 1][j];
2.当使用第i个木块且将第i个木块加到较长木块上:dp[i][j] = dp[i - 1][j - a[i]];
3.当使用第i个木块且将第i个木块加到较短木块,此时较短木块还是较短木块:dp[i][j] = dp[i - 1][j + a[i]] + a[i];
4.当使用第i个木块且将第i个木块加到较短木块,此时较短木块称为较长木块:dp[i][j] = dp[i - 1][a[i] - j] + a[i] - j;
要考虑周全每种情况,最后dp[n][0]
即为答案,若dp[n][0] == 0 || dp[n][0] == -1
时输出-1
代码:
/*************************************************************************
> File Name: p.cpp
> Author: Zcy
> Mail: [email protected]
> Created Time: 三 1/23 18:16:17 2019
************************************************************************/
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int a[55];
int sum[55] = {0};
int dp[55][500005];
int main () {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
sum[i] = sum[i - 1] + a[i];
}
memset(dp, -1, sizeof(dp));
dp[1][0] = 0;
dp[1][a[1]] = 0;
for (int i = 2; i <= n; i++) {
for(int j = 0; j <= sum[i]; j++) {
dp[i][j] = dp[i - 1][j];
if (a[i] - j >= 0) {
if (j + a[i] <= sum[i - 1] && dp[i - 1][j + a[i]] != -1) {
dp[i][j] = max(dp[i][j], dp[i - 1][j + a[i]] + a[i]);
}
int t = a[i] - j;
if (dp[i - 1][t] != -1) {
dp[i][j] = max(dp[i][j], dp[i - 1][t] + t);
}
} else {
if (j + a[i] <= sum[i - 1] && dp[i - 1][j + a[i]] != -1) {
dp[i][j] = max(dp[i][j], dp[i - 1][j + a[i]] + a[i]);
}
if (j - a[i] >= 0 && dp[i - 1][j - a[i]] != -1) {
dp[i][j] = max(dp[i][j], dp[i - 1][j - a[i]]);
}
}
}
}
if (dp[n][0] == 0) {
printf("-1\n");
} else {
printf("%d\n", dp[n][0]);
}
return 0;
}
如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢