查找图上距离N个节点的所有节点

问题描述

您和几个朋友正在玩棋盘游戏。游戏的棋盘被布置在一个大的,互连的图形中,该图形具有许多循环。每个玩家都从棋盘上的不同位置开始。轮到您时,您可以在1到6个6面骰子之间滚动任何东西(换句话说,从1-36掷骰子)。您如何确定您可能会从当前位置单次转弯进入的每个空间? (例如:我掷出13个。找到板上距离我13个空格的所有点。)您只能向前移动,但可以环回以遍历小于掷骰子的净总数

示例:如果这是您的图形,并且从左上角开始滚动6,则可以向下,向右,向右,向上,向左,向左移动。但是,您不能向右,向左,向右,向左,向右,向左移动

  o---o---o---o---o
  |       |   |
  o---o---o---o

有没有比深度优先搜索更好的算法?

解决方法

您完全不需要遍历图形即可解决此问题。

图可以通过其邻接矩阵进行编码:矩阵M使得M(i,j) = 1(如果从节点i到节点{{ 1}}和j(如果没有优势)。

此矩阵具有超酷的属性:对于任何非负整数M(i,j) = 0kM**k的{​​{1}}次幂,即 ie k乘以自身M倍)使得M =从k(M**k)(i,j)的不同步数。

如果i,则可以以j的精确度从节点(M**k)(i,j) > 0到达节点i。请注意,如果您确保每个节点都有自己的边缘 ie ,如果j的对角线充满k s,则可以完全M个动作中到达的节点与最多1个动作中可以到达的节点相同。

另请参阅:https://en.wikipedia.org/wiki/Adjacency_matrix#Matrix_powers

在大多数编程语言中,都有一些库可以非常有效地处理矩阵和矩阵运算,因此,将矩阵发挥功效可能比实际访问另一个图的节点快得多。

另一方面,如果图很大而k小,而您只对一个起始节点感兴趣,那么计算k可能比图遍历效率低,因为{{ 1}}回答了图形中每个节点的问题,而不仅仅是针对您感兴趣的起始节点。

但是,如果您对所有可能的起始节点都感兴趣,或者如果k接近图的直径,那么计算M**k很可能是最佳选择。

,

由于您可以绕圈子但不能直接回到您来自的节点的限制,实际上这是一个很有趣的问题。尤其是,您既不能做BFS或DFS来以较少的移动来修剪已经访问过的所有节点,也不可以巧妙地进行矩阵乘法。

相反,您可以使用DFS的变体,但是您必须同时跟踪可以到达某个节点的移动数量以及访问该节点时来自的节点,并且如果要访问,则只能修剪修剪之前曾经见过 exact 组合-如果您到达的节点较少,或者来自另一个节点,则不是这样。

Python的基本实现和示例:

def search(graph,start,moves):
    stack = [(start,-1)]
    distance = {i: set() for i in range(moves+1)}
    while stack:
        node,dist,prev = stack.pop()
        if (node,prev) in distance[dist]: continue
        distance[dist].add((node,prev))
        if dist < moves:
            stack.extend((x,dist+1,node) for x in graph[node] if x != prev)
    return {node for (node,prev) in distance[moves]}

# 1---2---3---4---5
# |       |   |
# 6---7---8---9
g = {1: [2,6],2: [1,3],3: [2,4,8],4: [3,5,9],5: [4],6: [1,7],7: [6,8: [3,7,9: [4,8]}
print(search(g,1,13))
# {8,2,6}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...