题目:
逗志芃在干了很多事情后终于闲下来了,然后就陷入了深深的无聊中。不过他想到了一个游戏来使他更无聊。他拿出n个木棍,然后选出其中一些粘成一根长的,然后再选一些粘成另一个长的,他想知道在两根一样长的情况下长度最长是多少。
输入格式:第一行一个数n,表示n个棍子。第二行n个数,每个数表示一根棍子的长度。
输出格式:一个数,最大的长度。
样例输入:4(回车)
1(空格)2(空格) 3(空格)1(回车)
样例输出:3
数据规模和约定:n<=15
前言:
蓝桥杯 试题 算法训练 无聊的逗 C++ 详解 - 未完善__Lyz_的博客-CSDN博客
上面这篇文章是我对 蓝桥杯 算法训练 《无聊的逗》的解析,不过是有问题的,但碰巧又通过的官网的测试样例,所以没有及时发现。
后经过一些网友的提醒才发现 自己解法有漏洞,但是那段时间比较忙,只偶尔回复一下网友,没有及时修改文章,之后给忘了。。。
(2022.03.25)今天上课时突然想起,在纸上推导一番后,目前可以解决所有情况。特地再写一篇文章,说明一下。
至于之前存在漏洞的文章,最不济也讲了一下DFS思想,我就先不删了,附上新文章的链接,之后再说。
开始:(读者应 对题目已有一定的了解)
对于本题,我们要做的就是将 一堆木棍 分为 相同的两堆。重点在于如何平均分?
根据上篇文章讲过的DFS思想,可以做到枚举所有情况。但还存在一个问题:无论如何分都无法均分为两堆。
例如:(1 1 2 3),然后我想的是:去除奇数最短的木棍,使木棍总和为偶数,"即可均分"。
但:(1 2 3 4 7)的时候就得去除最小的奇偶木棍1 2 了。
还有:(3 4 5 7)直接去除中间大小的5。
似乎没有规律。。。
这时,我们回顾上篇文章的DFS操作,对于某条木棍,除了选/不选,应该还有"放弃"的选项。
只不过之前文章的想法是直接在DFS外就想着把木棍们处理为 可均分的 大堆。
现在是 加多一个选择在DFS内。
还是举例,对于(1 1 2 3)。我们按照 选/不选 两种选择来操作的话。将
结果将是:0。即:无论如何都无法均分为两堆。但如果我们改进一下,加一种选择:"放弃"。情况又会不一样。
当然了,没有举例完,剩下的结果显而易见,我就不一一举例了,主要是展示不同分支的情况。
这时,得到的结果:3,也就是正确结果。
如上图,顺着黄色箭头返回,发现其都曾有"放弃"的选择,即抛弃一个1,以达到可平均分为两堆的情况。
继续:
还有例子:3 4 5 7
哪怕 要去除的木棍5 不前不后,改进后的DFS仍可以枚举出其 被放弃 的可能。
就不一一图示了(我也想偷偷懒),主要是同学们自己动手写写更能深刻理解过程。
总结:
综上所述,通过给DFS多加一种选择(双分支变三分支),则可以对所有木棍进行组合。(无需再做其他操作:去除木棍啥的,当然普通的优化是可以的,例如:最长的等于总和一半……)
DFS实现:参数(数组,数组长度,数组元素下标,左堆,右堆)
左堆:初始为所有木棍的总和
右堆:初始为0
通过dfs,左堆不断减少,右堆不断增加。
当左堆等于右堆时,结束,比较/更新结果。
当左堆小于右堆,剪枝。(之后dfs无意义)
附上代码:(更加简洁)
#include
using namespace std;
#include
//记录结果(不断刷新)
int MaxSum = 0;
// 深搜, 数组, 长度, 下标, (总)左堆, 右堆
void dfs(int ii[], int n, int x, int left, int right = 0)
{
//当满足 两堆相等 且 结果可更新
if (left == right && MaxSum < left)
{
MaxSum = left;
return;
}
//dfs剪枝(左堆小于右堆) 或 下标越界
if (left < right || x >= n)
{
return;
}
//正常dfs
else
{
dfs(ii, n, x + 1, left, right);//不选
dfs(ii, n, x + 1, left - ii[x], right + ii[x]);//选
dfs(ii, n, x + 1, left - ii[x], right);//放弃
return;
}
}
int main()
{
int add = 0;
int ii[15] = { 0 };
int n; cin >> n;
//录入数据 和 计算总和
for (int i = 0; i < n; i++)
{
cin >> ii[i];
add += ii[i];
}
//排序:升序
sort(ii, ii + n, greater());
//dfs
dfs(ii, n, 0, add);
//输出结果
cout << MaxSum;
return 0;
}
结束:
希望可以启发到各位 读者/同学 。
暂时就这样吧。
PS:本文配合之前的文章一起"食用"更佳。
蓝桥杯 试题 算法训练 无聊的逗 C++ 详解 - 未完善__Lyz_的博客-CSDN博客