算法是节点A连接到图中的节点B.

时间:2015-06-12 10:45:53

标签: python algorithm graph

我正在寻找一种算法来检查图形上两个任意节点之间的任何有效连接(最短或最长)。

我的图形固定为具有逻辑(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 - 应该在没有连接的情况下从主体上消失。

enter image description here

更新:

尽管许多已发布的答案可能都有效,但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)

4 个答案:

答案 0 :(得分:1)

要找到这个,你只需要在其中一个节点上运行简单的DFSBFS算法,它就会在图的连续组件中找到所有可到达的节点,所以如果您在算法运行期间找到了另一个节点,请将其标记下来。

答案 1 :(得分:1)

有一种方法可以使用Dijkstra找到路径。如果两个节点之间存在边缘,则将1设置为权重,如果没有节点,则将权重设为sys.maxint。然后,当计算最小路径时,如果它大于节点数 - 它们之间没有路径。

另一种方法是首先找到图的strongly connected components。如果节点位于相同的强组件上,则使用Dijkstra查找路径,否则没有连接它们的路径。

答案 2 :(得分:0)

你可以看看A* Path Finding Algorithm(它使用启发式方法使它比Dijkstra更有效,所以如果你的问题没有任何可以利用的东西,你可能最好使用Dijkstra的算法。你需要积极的权重。如果这不是你的图形中的东西,你可以简单地给每个边缘一个权重1)。

查看Wikipedia上的伪代码,A*通过获取当前节点的邻居从一个节点移动到另一个节点。 Dijkstra的算法保留一个邻接列表,以便它知道哪些节点相互连接。

因此,如果从节点H开始,您只能转到RD。由于这些节点未连接到其他节点,因此算法不会通过其他节点。

答案 3 :(得分:0)

您可以找到图表中的强连接组件(SCC),然后检查一个组件中是否有感兴趣的节点。在你的例子中,H-R-D将是第一个组件并且休息第二个,因此对于H和R结果将为真,但H和A为假。 请参阅此处的SCC算法:https://class.coursera.org/algo-004/lecture/53