Python 图论:寻找';n';长度(有一些限制)

Python 图论:寻找';n';长度(有一些限制),python,algorithm,recursion,graph-algorithm,Python,Algorithm,Recursion,Graph Algorithm,我的一个朋友给了我一个简单的挑战性问题。我想听听关于如何找到最佳解决方案的建议 这个问题涉及到计算在一个网格状的尺度上遍历一系列点的所有可能模式。我将得到一个数字'n',表示我必须移动多少次,我必须确定我可以移动n次网格的方式数。起点可以是任何一个点,所以我必须在每个起点上运行我的计算,我的答案是每个起点结果的总和 关于编程,我还是一个初学者,关于如何解决这个问题,我最好的猜测是使用图论。我首先创建了一个图来表示节点及其邻居。我故意把这个问题说得含糊不清,因为我想学习如何处理这类问题,而不是让专

我的一个朋友给了我一个简单的挑战性问题。我想听听关于如何找到最佳解决方案的建议

这个问题涉及到计算在一个网格状的尺度上遍历一系列点的所有可能模式。我将得到一个数字'n',表示我必须移动多少次,我必须确定我可以移动n次网格的方式数。起点可以是任何一个点,所以我必须在每个起点上运行我的计算,我的答案是每个起点结果的总和

关于编程,我还是一个初学者,关于如何解决这个问题,我最好的猜测是使用图论。我首先创建了一个图来表示节点及其邻居。我故意把这个问题说得含糊不清,因为我想学习如何处理这类问题,而不是让专家来帮我解决整个问题。下面是我的图形在Python3(字典)中的一个示例表示

我的真实图要大得多,每个节点通常至少有3-4个邻居。让我们假设给定的“n”是6,这意味着我需要返回所有可能的有效路径,包括移动6次。我可以重新访问节点,因此有效路径可以是a-b-a-b-a-b。“有效”路径的另一个例子是a-b-a-c-d-c或e-b-a-c-a-b,因为我们可以从任何起点开始

对于如何最好地解决这个问题,我有点不知所措。递归作为一种可能的解决方案出现在我的脑海中,我遍历所有可能的路径,并在每次到达路径的“末端”时增加一个计数器。我考虑过的另一个可能的解决方案是,在每个节点上,计算可能的移动,并将其与运行计数相乘。例如,从a开始,我有两个动作。如果我导航到“b”,我有3个动作。如果我导航到“c”,我有两个移动。在这一点上,我有1*3*2个动作。这可能是一个完全错误的方法…只是我的一个想法

对于某些节点的约束,实际问题要复杂得多(您可以访问它多少次,如果某个节点序列之前被击中,则禁止访问它的规则,等等),但我现在将省略细节。我要说的是,给定这些约束条件,我的算法必须知道以前访问的节点的模式是什么。例如,在第五步,我必须能够随时参考前面的四步


我很想听听关于如何最好地解决上述“更简单”问题的建议

查看深度优先搜索(DFS)。我的想法很简单:使用递归DFS,使用计数器保存在进行“n”个移动后找到的每个节点。您需要构建给定数据的无向图表示形式,以便在图上运行DFS算法。

以下是您给出的案例的最简单答案。一旦您以“转换映射”的形式创建了图形(可以是一个字典,如您所示),那么以下代码将起作用:

def myDFS(trans_dict,start,length,paths,path=[]): 
    path=path+[start] 
    if len(path)==length:
        paths.append(path) 
    else:
        for node in trans_dict[start]:
            myDFS(trans_dict,node,length,paths,path)
如果您想知道使用给定长度的路径遍历地图的方法的数量,那么只需要
len(path)

例如:

trans_dict = {0:[1,2],1:[2,3],2:[0,3],3:[3]}
paths = []
length = 3

for a in trans_dict:
    myDFS(trans_dict,a,length,paths)

print paths # [[0, 1, 2], [0, 1, 3], [0, 2, 0], [0, 2, 3], [1, 2, 0], [1, 2, 3], [1, 3, 3], [2, 0, 1], [2, 0, 2], [2, 3, 3], [3, 3, 3]]
print len(paths) # 11

答案来源于此问答:

由于某些节点的约束(您可以访问它的次数,如果某个节点序列之前被击中,则禁止访问它的规则等),实际问题要复杂得多。
使问题成为NP难问题。如果在包含
n
节点的图中有长度
n
的路径,并且最多可以访问每个节点一次,那么就有哈密顿路径(HP)。然而,确定是否存在HP是NP难的(这意味着没有已知的有效解决方案,大多数人认为不存在)。我知道这个问题是一个版本的变体,您只能访问每个节点一次(HP),而且我也知道有一个精确且正确的解决方案。我可能在描述约束时出错,所以我会更具体一些。有时某些节点只能访问x次。这个问题可能会给你n=10,节点“a”、“c”和“d”最多只能访问3次。有时,你可以给节点v1、v2、…、vn-每个节点最多只能访问一次,路径长度为
n
,你就得到了一个HP。我用递归DFS找到了一个解决方案……但是,我意识到这可能不是解决这个问题的理想方法,因为程序将永远用大n值运行。干得好!您可以使用本地堆栈来实现使用相同思想的迭代解决方案;这将有助于避免n的大值的堆栈溢出,并且可能会使算法总体上更有效。DFS是这类问题的标准算法,但我相信有一些方法可以优化算法,使其更有效地解决您试图解决的特定问题。
trans_dict = {0:[1,2],1:[2,3],2:[0,3],3:[3]}
paths = []
length = 3

for a in trans_dict:
    myDFS(trans_dict,a,length,paths)

print paths # [[0, 1, 2], [0, 1, 3], [0, 2, 0], [0, 2, 3], [1, 2, 0], [1, 2, 3], [1, 3, 3], [2, 0, 1], [2, 0, 2], [2, 3, 3], [3, 3, 3]]
print len(paths) # 11