我正在寻找一种算法来检查图形上两个任意节点之间的任何有效连接(最短或最长)。
我的图形固定为具有逻辑(x,y)坐标的网格,具有北/南/东/西连接,但是可以随机删除节点,因此您不能假设使用最接近的坐标来获取边缘目标总是会让你到那里。
代码在python中。数据结构是每个节点(对象)都有一个连接节点列表。列表元素是对象引用,因此我们可以递归地搜索该节点的连接节点列表,如下所示:
for pnode in self.connected_nodes:
for cnode in pnode.connected_nodes:
...etc
我已经包含了一个图表,显示了节点如何映射到x,y coords以及它们如何在北/东/南/西连接。有时缺少节点(即J和K之间),有时缺少边缘(即G和H之间)。节点和边缘的存在是不稳定的(尽管当我们运行算法时,它正在及时获取固定的快照),并且只能通过检查每个节点的连接节点列表来确定。
算法需要对两个节点之间是否存在有效连接产生简单的真/假。递归每个连接节点列表会爆炸所需的操作数量 - 如果节点距离n个边缘,则最多需要4 ^ n个操作。我的理解就像Dijistrka的算法一样,通过找到基于边权重的最短路径,但是如果根本没有连接那么它还能工作吗?
对于某些背景,我使用它来模拟2D可破坏对象。每个节点代表一个材料块,如果一个或多个节点没有与其余材料的连接,那么它应该分开。在图中 - D,H,R - 应该在没有连接的情况下从主体上消失。
更新:
尽管许多已发布的答案可能都有效,但DFS快速,简单且非常合适。我并不热衷于在具有高权重的节点之间粘贴额外边缘以使用Dijkstra的想法,因为节点本身可能会消失以及边缘。 SSC方法似乎更适合区分强连接和弱连接的图形部分,如果在G和H之间存在单个边缘,则在我的图形中可以起作用。
这是我的DFS搜索实验代码,它创建了与图中所示相同的图形。
class node(object):
def __init__(self, id):
self.connected_nodes = []
self.id = id
def dfs_is_connected(self, node):
# Initialise our stack and our discovered list
stack = []
discovered = []
# Declare operations count to track how many iterations it took
op_count = 0
# Push this node to the stack, for our starting point
stack.append(self)
# Keeping iterating while the stack isn't empty
while stack:
# Pop top element off the stack
current_node = stack.pop()
# Is this the droid/node you are looking for?
if current_node.id == node.id:
# Stop!
return True, op_count
# Check if current node has not been discovered
if current_node not in discovered:
# Increment op count
op_count += 1
# Is this the droid/node you are looking for?
if current_node.id == node.id:
# Stop!
return True, op_count
# Put this node in the discovered list
discovered.append(current_node)
# Iterate through all connected nodes of the current node
for connected_node in current_node.connected_nodes:
# Push this connected node into the stack
stack.append(connected_node)
# Couldn't find the node, return false. Sorry bud
return False, op_count
if __name__ == "__main__":
# Initialise all nodes
a = node('a')
b = node('b')
c = node('c')
d = node('d')
e = node('e')
f = node('f')
g = node('g')
h = node('h')
j = node('j')
k = node('k')
l = node('l')
m = node('m')
n = node('n')
p = node('p')
q = node('q')
r = node('r')
s = node('s')
# Connect up nodes
a.connected_nodes.extend([b, e])
b.connected_nodes.extend([a, f, c])
c.connected_nodes.extend([b, g])
d.connected_nodes.extend([r])
e.connected_nodes.extend([a, f, j])
f.connected_nodes.extend([e, b, g])
g.connected_nodes.extend([c, f, k])
h.connected_nodes.extend([r])
j.connected_nodes.extend([e, l])
k.connected_nodes.extend([g, n])
l.connected_nodes.extend([j, m, s])
m.connected_nodes.extend([l, p, n])
n.connected_nodes.extend([k, m, q])
p.connected_nodes.extend([s, m, q])
q.connected_nodes.extend([p, n])
r.connected_nodes.extend([h, d])
s.connected_nodes.extend([l, p])
# Check if a is connected to q
print a.dfs_is_connected(q)
print a.dfs_is_connected(d)
print p.dfs_is_connected(h)
答案 0 :(得分:1)
答案 1 :(得分:1)
有一种方法可以使用Dijkstra找到路径。如果两个节点之间存在边缘,则将1设置为权重,如果没有节点,则将权重设为sys.maxint
。然后,当计算最小路径时,如果它大于节点数 - 它们之间没有路径。
另一种方法是首先找到图的strongly connected components。如果节点位于相同的强组件上,则使用Dijkstra查找路径,否则没有连接它们的路径。
答案 2 :(得分:0)
你可以看看A* Path Finding Algorithm
(它使用启发式方法使它比Dijkstra更有效,所以如果你的问题没有任何可以利用的东西,你可能最好使用Dijkstra的算法。你需要积极的权重。如果这不是你的图形中的东西,你可以简单地给每个边缘一个权重1)。
查看Wikipedia上的伪代码,A*
通过获取当前节点的邻居从一个节点移动到另一个节点。 Dijkstra的算法保留一个邻接列表,以便它知道哪些节点相互连接。
因此,如果从节点H
开始,您只能转到R
和D
。由于这些节点未连接到其他节点,因此算法不会通过其他节点。
答案 3 :(得分:0)
您可以找到图表中的强连接组件(SCC),然后检查一个组件中是否有感兴趣的节点。在你的例子中,H-R-D将是第一个组件并且休息第二个,因此对于H和R结果将为真,但H和A为假。 请参阅此处的SCC算法:https://class.coursera.org/algo-004/lecture/53。