2015-06-12 64 views
3

我正在尋找一種算法來檢查圖上兩個任意節點之間的任何有效連接(最短或最長)。算法是節點A在圖中連接到節點B

我的圖被固定在一個網格上,它具有北/南/東/西連接的邏輯(x,y)座標,但節點可以隨機移除,因此您不能假定採用最接近目標總是會讓你到那裏。

代碼是在Python中。數據結構是每個節點(對象)都有一個連接節點的列表。列表中的元素是對象裁判,這樣的話我們可以搜索連接節點的節點的列表遞歸,就像這樣:

for pnode in self.connected_nodes: 
    for cnode in pnode.connected_nodes: 
     ...etc 

我已經包括顯示節點如何映射到X,Y COORDS圖以及它們是如何連接在北/東/南/西。有時缺少節點(即J和K之間),有時缺少邊(即G和H之間)。節點和邊的存在是不斷變化的(儘管當我們運行該算法時,它會及時獲取固定的快照),並且只能通過檢查每個節點的連接節點列表來確定。

該算法需要產生一個簡單的真/假以確定兩個節點之間是否存在有效的連接。遞歸遍歷每個連接節點列表會爆炸所需的操作數量 - 如果節點距離較遠,則最多需要4^n次操作。我的理解是類似於Dijistrka的算法通過找到基於邊權重的最短路徑,但如果根本沒有連接,那麼它是否仍然有效?

對於一些背景,我使用它來模擬2D可破壞對象。每個節點代表一塊材料,並且如果一個或多個節點沒有連接到材料的其餘部分,那麼它應該分離。在圖中 - D,H,R - 應該從主體上剝離,因爲它們沒有連接。

enter image description here

UPDATE:

雖然許多貼出答案可能很好地工作的,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) 
+1

您是否知道networkx庫?像[this](http://networkx.github.io/documentation/latest/reference/generated/networkx.algorithms.shortest_paths.generic.has_path.html)會有幫助嗎? – Ioannis

+0

@loannis看起來不錯。挖掘它們的源代碼,它看起來像使用dijisktra或類似的,如果找不到路徑則拋出異常。我有一些類似16行代碼的工作代碼,所以我會堅持,而不是導入一個全新的模塊。儘管如果我需要做更多的圖/樹算法,它可能值得切換到像networkx這樣的東西。我有一個習慣於重新發明輪子的機會。 – Oliver

+0

確實,指針更多地提高了對NetworkX的認識,這在其他場合可能會有用。 – Ioannis

回答

2

要了解這一點,你只需要運行簡單的DFSBFS算法上的一個節點,它會發現圖的連續分量內的所有節點到達,所以你只要將其標記下來,如果你在算法運行期間找到了另一個節點。

+1

直觀上DFS聽起來像最慢的方法,但通過它思考它越來越有意義。一些谷歌搜索表明,這是檢查連接圖形的常用方法。我已將測試代碼包含在問題中以供參考。 – Oliver

1

有一種方法可以使用Dijkstra查找路徑。如果兩個節點之間存在邊緣,則將1放在重量上,如果沒有節點,則放置sys.maxint的權重。然後在計算最小路徑時,如果它大於節點數量 - 它們之間沒有路徑。

另一種方法是首先找到該圖的strongly connected components。如果節點位於同一強組件上,則使用Dijkstra查找路徑,否則不存在連接它們的路徑。

0

你可以看看A* Path Finding Algorithm(它使用啓發式方法使它比Dijkstra更有效率,所以如果你的問題沒有什麼可以利用的話,那麼使用Dijkstra算法可能會更好。如果這不是你在圖表中的東西,那麼你可以簡單地給每條邊加權1)。

查看維基百科上的僞代碼,A*通過獲取當前節點的鄰居從一個節點移動到另一個節點。 Dijkstra算法保留一個鄰接表,以便它知道哪些節點彼此連接。

因此,如果你從節點H開始,你只能去RD。由於這些節點沒有連接到其他節點,所以算法不會經過其他節點。

0

您可以找到圖的強連通組件(SCC),然後檢查一個組件中是否有感興趣的節點。在你的例子中,H-R-D將是第一個分量,然後是第二個分量,因此對於H和R,結果將爲真,但H和A爲假。 請參閱此處的SCC算法:https://class.coursera.org/algo-004/lecture/53

相關問題