C++ 硬币堆

2025 年 3 月 25 日 | 阅读 3 分钟

算法竞赛中的常见问题主要涉及 “硬币堆” 问题。本文将介绍数学观察和高效算法。让我们详细了解如何解决它。

问题陈述

您有两堆硬币 A 和 B,分别有 A 和 B 个硬币。您可以执行任意数量的以下类型的操作:

  • 从 A 堆中移除 2 个硬币,从 B 堆中移除 1 个硬币。
  • 从 A 堆中移除 1 个硬币,从 B 堆中移除 2 个硬币。

您的任务是找出您是否可以通过这些操作使两堆硬币都变空。

一些主要观察

为了解决这个问题,我们必须观察一些关键属性。

1. 硬币总数减少

由于两种操作都会使两堆硬币的总数减少 3(从 A 堆移除 2 个 + 从 B 堆移除 1 个,或从 A 堆移除 1 个 + 从 B 堆移除 2 个),因此如果总和 A + B 可以被 3 整除,则整堆硬币必须被清空。

2. 两者之间的平衡

每次操作都会从一堆中移除比另一堆更多的硬币。为了防止一堆硬币在另一堆之前用完,任何一堆的硬币数量都不应超过另一堆的两倍。

这意味着

  • A <= 2 * B
  • B <= 2 * A

如果其中一个条件不满足,将无法平衡两堆硬币并继续进行有效操作。

示例

输出

 
5
1 8
NO
23 56
NO
2 4
YES
1 8
NO
35 70
YES   

说明

所解释的 C++ 程序通过确定两堆硬币 A1 和 B1 是否可以通过一组定义的操作来清空,即从一堆中移除 2 个硬币,从另一堆中移除 1 个硬币,反之亦然,从而解决了 “硬币堆” 问题。isEmptyPiles 函数验证两个基本条件:一,硬币总数 (A1 + B1) 是否可以被 3 整除,因为每次操作都会使硬币总数减少 3;二,任何一堆的硬币数量是否不超过另一堆的两倍,因为它无法进行有效操作。如果这两个条件中的任何一个失败,函数将返回 false 并输出 “NO”;否则,它将返回 true 并输出 “YES”。 之后,主 函数 适应多个测试用例,读取输入,并调用 isEmptyPiles 来判断并打印每个测试用例的结果。

结论

总之,“硬币堆” 问题是一个算法的基准挑战;它需要数学洞察力与熟练的问题解决能力的结合。通过使用两个关键观察——硬币总数必须可以被 3 整除,并且任何一堆的硬币数量都不能超过另一堆的两倍,可以相对更容易地确定是否可以通过所述操作清空两堆。该解决方案使问题变得更简单,并且每个测试用例的时间复杂度为 O(1)O(1),实现了最优性。

它是竞争性编程的完美选择,可以通过简单的算术检查和条件获得快速答案。理解其背后的推理对于理解类似的组合问题和使用数学属性来制定高效算法至关重要。