硬币移除问题的算法
问题: 现有n个硬币排成一排。只允许对硬币进行以下操作:
移除一个正面向上的硬币,同时翻转与其相邻的硬币。
问有哪些排列是可以达到移除所有的硬币的。
例如,反正正正反 是可以移除的(正空反正反,空空反正反,空空正空正,空空空空正)。但是像 反正反正反 是没法移除的。
我尝试编程解决这个问题,但是感觉有点吃力。似乎还和移除的顺序有关。例如上面的 反正正正反 如果先移除当中的一个硬币,就变成 反反空反反 了,然后就无法移除了。这样枚举的时候就不能随意移除一枚正面硬币了……
求指教。任意语言、伪代码都行。(不知道这个问题在数学上有没有什么特殊的方法求解?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我来练习下 Scheme :-)
编译与运行:
0 表示反面,1 表示正面,2 表示空位。
再补充一个 Haskell 版的:
个人觉得不会留空,如果是竖向堆叠的话,会在重力的作用下掉下去……
如果有留空,则会出现第三种状态,所以先按2种状态来做吧。
1
思路首先最简单的,罗列从{}到{1,1,1,1,1}的所有可能性。然后根据f(A)=B的关系将它们连线。大概会组成一个这样的关系:
这样问题就变成了遍历一棵树了。然后时间复杂度和空间复杂度都是O(n2)
语言是JavaScript。为了最快实现用了递归=w=所以时间复杂度和空间复杂度俺都不知道……
明显是数学问题,稍微推倒一下可以发现:
f(n) = f(n - 1) + 2(n - 2) + 1
=>
f(2n) = 2f(2n - 1)
f(2n + 1) = 2f(2n) + 1
或者简单地说
f(n) = 2f(n - 1) + n%2
f(n)是答案。
突然发现太严格的证明我也写不出来,简单说下思路吧。
这个递归大部分都非常的显然。
定义
f(n)
为答案,考虑,令集合S(n)
为长度为n的答案集合,显然f(n) = Card(S(n))
那么对于长度为
n - 1
的S(n - 1)
,把1
放到S(n - 1)
中的每个序列后面,同时反转1
前面的东西,这显然是一个方案。然后……考虑在
S(n - 2)
的尾巴放两个0和10……以及一个很特殊的情况就是00000...11得到递归式子
S(n) = S(n - 2) + 00 | S(n - 2) +10 | S(n - 1) + 1 | 000...11
于是
f(n) = f(n - 1) + 2f(n - 2) + 1
注意n > 2
各种乱搞之后得到前面的式子。。实际上f(n)的二进制形式就是101010101...010当n为偶数,1010101010...101当n为奇数。
最后就得到
f(n) = 2f(n - 1) + n % 2
. 差不多是这样的,中间有一些什么不重复之类的就没有严格证明了……如果有兴趣的话随便玩玩吧。不说范围的算法题都是刷流氓