0
点赞
收藏
分享

微信扫一扫

蓝桥杯 算法训练 无聊的逗 简单版C++

黎轩的闲暇时光 2022-03-14 阅读 106

        起初看到题目,想了许久仍是没有思路,看了一位大佬用dp做的思路,深受启发

LanQiao-ALGO-1004 无聊的逗 (动态规划: 0-1背包问题) -- (LeetCode 416. 分割等和子集 变种题)_Mr.xiao的博客-CSDN博客

但是我只看懂了dp部分,其他还是略显复杂没有细究。

我自己在不断地debug中找到了更为简便的方法。

思路如下:

       可以设背包容量为sum/2,dp[i][j]就是把1~i个重量与长度相等的棍子放进容量为j的背包里

       、若装进去的最大长度等于sum/2(意思是恰好有m根棍子能拼接成总长度的一半),则剩下的n-m根棍子也能拼接sum/2的长度

       二、实现一的前提是,棍子的总长度是偶数,这样才能分出两条拼接长度相等的棍子

        比如 1 2 3 1,总长度是7,sum/2是3,我们需要拿掉一个1,总长度变成6,剩下的1 2 3就可以分为 1 2 和3,所以最长长度为3。

        那么我们怎么知道拿出哪一根棍子才好呢?

        1.首先我们得拿出一根棍子,使总长度为偶数。

        2.棍子被拿出一条后总长度尽量大

        总结:从最小的棍子开始判断,若拿出该棍子后总长度为偶数即符合条件!

代码如下

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

int main() {
	int n, sum = 0;
	cin >> n;
	int A[n + 1] = {0};
	for (int i = 1; i <= n; i++) {
		cin >> A[i];
		sum += A[i];
	}
	sort(A, A + n + 1);//需对长度进行排序

	if (sum % 2) {//总长度为奇数的情况
		for (int i = 1; i <= n; i++) {
			if ((sum - A[i]) % 2 == 0) {//长度最小并使总长度为偶数的长度
				sum -= A[i];
				for (int j = i; j <= n; j++)
					A[j] = A[j + 1];
				n--;
				break;

			}
		}
	}
	int dp[n + 1][sum / 2 + 1];
	memset(dp, 0, sizeof(dp));
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= sum / 2; j++) {
			if (A[i] > j) {
				dp[i][j] = dp[i - 1][j];
			} else {
				dp[i][j] = max(dp[i - 1][j],A[i] + dp[i - 1][j - A[i]])
			}
		}
	}
	if (dp[n][sum / 2] == sum / 2) {//最后判断一下有没有m根棍子能凑成sum/2的长度
		cout << dp[n][sum / 2];
	} else {
		cout << 0;
	}
}
举报

相关推荐

0 条评论