洛谷P1651塔

题目描述

小明很喜欢摆积木,现在他正在玩的积木是由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: 296763002@qq.com
	> 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;
}

转载请注明出处!!!

如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值