编写在图形中查找哈密顿路径的Python函数

编写在图形中查找哈密顿路径的Python函数,python,recursion,hamiltonian-cycle,Python,Recursion,Hamiltonian Cycle,我试着写一个函数,将一个正整数n作为输入,并将整数1到n按顺序排列,这样每个相邻数字的和就是一个完美的平方(如果存在这样的顺序)。我意识到,如果我创建一个图,其中顶点是数字,如果两个顶点的和是一个完美的正方形,那么两个顶点之间有一条边,那么这个问题就相当于试图在图中找到哈密顿路径。所以,我试图写一个函数,在给定的图中找到一个哈密顿图,如果它存在的话。这是我的密码: def hampath_finder(moves, start, path=None): if path is None:

我试着写一个函数,将一个正整数n作为输入,并将整数1到n按顺序排列,这样每个相邻数字的和就是一个完美的平方(如果存在这样的顺序)。我意识到,如果我创建一个图,其中顶点是数字,如果两个顶点的和是一个完美的正方形,那么两个顶点之间有一条边,那么这个问题就相当于试图在图中找到哈密顿路径。所以,我试图写一个函数,在给定的图中找到一个哈密顿图,如果它存在的话。这是我的密码:

def hampath_finder(moves, start, path=None):
    if path is None:
        path = []
    if len(path) == bound:
        return path
    if not path:
        path = path + [start]
    for candidate in moves[start]:
        if candidate not in path:
            path = path + [candidate]
            new_path = hampath_finder(moves, candidate, path)
            if new_path:
                return new_path
            else:
                continue
    else:
        return None
    return None
“Moves”是图形的字典(变量“graph”已经被使用,我不擅长命名变量),其中每个顶点都是一个键,每个键的值都是一个包含与键顶点相邻的其他顶点的列表。例如,当输入为15时,这是字典:

{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], 10: [6, 15], 11: [5, 14], 12: [4, 13], 13: [3, 12], 14: [2, 11], 15: [1, 10]}
起点是哈密顿路径的起点。(我曾尝试在没有起点的情况下编写此函数,使函数本身尝试将每个点作为起点,但它变得复杂。目前,我只是自己迭代所有顶点。)

我知道,对于数字15,它应该给我以下列表:

[9, 7, 2, 14, 11, 5, 4, 12, 13, 3, 6, 10, 15, 1, 8]
但是,它给了我以下列表:

[9, 7, 2, 14, 11, 5, 4, 12, 13, 3, 1, 8, 15, 10, 6]
考虑到这个函数是如何运行的,我意识到一旦它变为1,它首先会加上8作为下一个数字。但是,8在除1之外的顶点之间没有边。老实说,我不知道它接下来会做什么。我意识到,一旦它没有可能的候选人去尝试,它就需要回溯,回到最后一个正常的位置。我不知道如何实现这一点

如何解决此问题?另外,如何改进代码

我是Python新手,所以如果这个问题很琐碎或者我的代码很糟糕,我深表歉意

编辑:我想我解决了主要问题,现在它返回正确的列表。以下是新代码:

def hampath_finder(moves, start, path=None):
    if path is None:
        path = []
    if len(path) == bound:
        return path
    if not path:
        path = path + [start]
    for candidate in moves[start]:
        if candidate not in path:
            new_path = hampath_finder(moves, candidate, path + [candidate])
            if new_path:
                return new_path
我认为问题在于,一旦我们到达了死胡同,错误的路径已经被添加到列表
path
,这就是为什么前面代码的输出中有一个8

现在,问题是函数在返回列表后返回
None
。这是我对数字15运行此函数时的输出,即图是我前面提到的字典:

[8, 1, 15, 10, 6, 3, 13, 12, 4, 5, 11, 14, 2, 7, 9]
None
如何修复此问题,使其不会返回
None
?顺便说一句,我自己还是要尝试每一个数字作为起点。我是这样做的:

for number in range(1, 16):
    if hampath_finder(moves, number):
        print(hampath_finder(moves,number))
换句话说,我必须手动尝试每个数字作为路径的起点。如何调整原始函数,使其不需要起点,并尝试所有可能的数字本身

此外,即使对于较小的数字,此函数也需要较长的时间。我怎样才能使它更有效率

编辑:我意识到包含整个函数而不仅仅是哈密顿路径部分更有帮助,因为有些变量是未定义的

from math import sqrt


def adjacent_square(bound):
    def blueprint(bound):
        graph = {}
        for number in range(1, bound + 1):
            pos_neighbours = []
            for candidate in range(1, bound + 1):
                if sqrt(number + candidate) == int(sqrt(number + candidate)) and number != candidate:
                    pos_neighbours.append(candidate)
            graph[number] = pos_neighbours
        return graph

    graph = blueprint(bound)

    def hampath_finder(mapping, start, path=None):
        if path is None:
            path = []
        if len(path) == bound:
            return path
        if not path:
            path = path + [start]
        for candidate in mapping[start]:
            if candidate not in path:
                new_path = hampath_finder(mapping, candidate, path + [candidate])
                if new_path:
                    return new_path

    for num in range(1, bound+1):
        if hampath_finder(graph, num):
            print(hampath_finder(graph, num))
            break
    else:
        print("No such order exists.")

函数
blueprint
通过检查每个可能对的总和来创建图形。我已经解释过汉帕斯查找器了。之后,我尝试使用
for
循环将每个数字作为路径的开始。

我认为您得到
的原因是因为在
hampath\u finder
函数中,如果新路径:您只返回一个值
。如果没有新路径且函数返回,Python将返回
None
。您可以通过此示例看到:

def testfunct(测试):
如果测试:
返回真值
打印(testfunct(假))
此外,您还要计算两次hampath_查找器。一次查看它是否存在,然后再次打印它。我将更改您代码的这一部分:

for num in range(1, bound+1):
    if hampath_finder(graph, num):
       print(hampath_finder(graph, num))
       break
更像这样:

for num in range(1, bound+1):
    this_path = hampath_finder(graph, num)
    if len(this_path) > 0:
       print(this_path)
       break
这将有助于降低速度


然而,粗略地看一下这个问题,似乎它是一个NP完全问题。所以这将是非常缓慢的。有一些研究论文的更快实现超出了StackOverflow的范围。此外,如果速度是必需的,那么你可能想把实现转换成C或C++之类的东西。

< P>我认为你得到<代码>没有< <代码>的原因是因为在<代码> HAMPATHOFFIDENU/SCOR>函数中,如果NeXYPATH:< /C> >,只返回值<代码>。如果没有新路径且函数返回,Python将返回
None
。您可以通过此示例看到:

def testfunct(测试):
如果测试:
返回真值
打印(testfunct(假))
此外,您还要计算两次hampath_查找器。一次查看它是否存在,然后再次打印它。我将更改您代码的这一部分:

for num in range(1, bound+1):
    if hampath_finder(graph, num):
       print(hampath_finder(graph, num))
       break
更像这样:

for num in range(1, bound+1):
    this_path = hampath_finder(graph, num)
    if len(this_path) > 0:
       print(this_path)
       break
这将有助于降低速度


然而,粗略地看一下这个问题,似乎它是一个NP完全问题。所以这将是非常缓慢的。有一些研究论文的更快实现超出了StackOverflow的范围。此外,如果速度是必需的,那么你可能想把实现转换成C或C++之类的东西。预期输出和生成的输出的
移动
启动
是什么?另外,
path
None?或者您正在传递一个
路径
?是否只返回
False
,而不是在else中返回
None
?我已经尝试了这两种方法,但输出没有改变。区别是什么?
如果没有
应该有错误。看起来您的代码中存在错误。哪个if语句是应该与之配对的
else:returnnone
?我现在编辑了这篇文章以删除该部分。在我编写这个函数时,它可能对某些事情有用,但是现在,删除整个
else:returnnone
part对输出没有影响。我