寻找平方链排列的算法

14

排列称为平方链当且仅当连续的数之和始终为完全平方数。例如,

8 1 15 10 6 3 13 12 4 5 11 14 2 7 9 16

是数字1到16的平方链排列。我想编写一个程序,找到数字1到n的平方链排列,其中n的取值范围为1到100。

最简单的方法是按字典顺序遍历所有n个数字的排列(我知道如何编写这个算法),并检查平方链条件,但对于较大的n,这将花费很长时间。

比较好的方法是逐个选择排列中的数字,并检查刚选择的数字加上前一个数字是否为完全平方数,希望能够完成整个排列。但是这样会经常回溯,效率可能不高。

有更好的方法吗?此问题是否为众所周知的问题?感谢您的帮助。


1
例如,1、2、3是否保证存在? - parapura rajkumar
@MitchWheat 看起来我们有些混淆,他得到了两种类型的投票。 - Yuriy Faktorovich
1
为什么要关闭投票?原帖已经有两个解决方案了吗? - parapura rajkumar
你为什么说回溯法只是“稍微”好一点呢?我没有彻底分析过它,也许你已经分析了,但我猜想这种方法比原始方法快得多。 - smendola
1个回答

6
有趣的问题; 我会尝试解答。将问题重述为TSP
创建一个图,其中节点是从1到100的整数(最大考虑的n)。现在连接ij,如果i+j是完全平方数。问题问道,“是否存在一个通过节点1n哈密顿路径?”
创建一次图,也许你可以微调i的路径,一旦你拥有了它,就可以包括i+1
这是直至14的图形:
                   13 --(25)-- 12 --(16)-- 4 --(9)-- 5 --(16)-- 11
                    |                                           |
                  (16)                                         (25)
                    |                                           |
8 --(9)-- 1 --(4)-- 3 --(9)-- 6 --(16)-- 10                     14
                                                                |
                                                               (16)
                                                                |
                                           9 --(16)-- 7 --(9)-- 2

在加入14之前,这个图并不连通,即使在加入14后也没有哈密顿路径。这里有一种可爱的方法来画出加入15之后的图,它可以轻松地展示如何在仍然拥有哈密顿路径的情况下添加16和17:

    12  11  10  09  08
13
                    07
14
                    06
15
                    05
    01  02  03  04

在图纸上画出这个图形,并连接对角线和反对角线(例如12-13,14-11等等以及09-07,10-06等等),它们是成对得到9或16的方法。在这里,我忽略了1和3之间的边缘,因为它没有帮助。想象一下从8到1沿对角线发射一个球,当它撞到一个数字时,它会以直角反弹。球沿着您给出的哈密顿路径行进(其中16被删除)。
要获得16的路径,只需将其添加到左下角即可。要获得17,请将其附加到球进入8的路径上。
有合理的算法可用于查找哈密顿路径,而此方法可能比根据您建议的任一方法检查每个n要快。
我得出结论,对于n<=25,只有15、16、17、23、25存在解决方案。瞧!这个序列在OEIS中存在。根据该页面,猜测所有n>24都存在解决方案,因此显然已知该问题,尽管我不一定称之为众所周知。

我认为这张图需要进行一些更正:节点10连接的是节点15,而不是节点5。节点15将形成一个回路返回到节点1。此外,节点3连接到节点13,然后连接到节点12。 - Glenn
@Glenn 谢谢。Ascii艺术不是我的长项。 - PengOne
@templatetypedef 定义'高效'的含义;-) 从例子来看,也许是这样,但事实上,证明对于所有n>25都存在一条路径仍然是一个未解决的问题,这让我认为,如果有的话,这并不容易。 - PengOne
节点和边 1:[3,8,15] 2:[7,14] 3:[1,6,13] 4:[5,12] 5:[4,11] 6:[3,10] 7:[2,9] 8:[1] 9:[7,16] 10:[6,15] 11:[5,14] 12:[4,13] 13:[3,12] 14:[2,11] 15:[1,10] 16:[9] - Glenn
这里是使用回溯法的JS实现。它还利用了@PengOne的“边缘”思想,作为优化,而不是循环遍历所有可能的“to”数字来查找有效的平方。不确定它是否真正无错;它似乎只能找到n=14、n=15、n=16的解决方案。也许没有其他的解决方案。它只能处理n=40以下的情况,在这一点上,它变得太慢而无法在浏览器中运行。http://jsfiddle.net/smendola/vHVkX/ - smendola
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接