簡體   English   中英

使用python優化圖形中檢測周期的算法

[英]Optimizing the algorithm of detecting cycle in a graph using python

我已經使用dfs實現了此代碼,以檢測圖形中是否有一個循環,如果有,還打印該循環的頂點。 如果有多個循環,則只需打印找到的第一個循環即可。 但是OJ以某種方式告訴我,對於某些測試用例而言,效率還不夠高。 關於如何提高這段代碼效率的任何想法嗎?

我一直在認真思考如何改善這一點,但沒有任何進展。 我想也許我應該嘗試使用除dfs之外的其他算法?

# using python3

from collections import defaultdict


class Graph():
    def __init__(self, V):
        self.V = V
        self.graph = defaultdict(list)

    def add_edge(self, u, v):
        self.graph[u].append(v)

    def dfs_walk(self, u):
        # List to contain the elements of a circle
        list_circle = list()
        # Mark visited vertexes
        visited = list()
        stack = [u]
        while stack:
            v = stack.pop()
            visited.append(v)
            # If already in list_circle, means there is a circle.
            if v in list_circle:
                return True, list_circle[list_circle.index(v):], visited
            # If v is not in list_circle and it has neighbor, collect it in the list,
            # go to next vertex. If it hasn't neighbor, check the left vertex
            else:
                # the next vertex is the first neighbor of this vertex
                if len(self.graph[v]) > 0:
                    stack.extend(self.graph[v])
                    list_circle.append(v)

        # Didn't find a circle in this round.
        return False, list_circle, visited

    def is_cyclic(self):
        control = [-1] * self.V
        for i in range(self.V):
            if control[i] == -1:
                flag, list_circle, visited = self.dfs_walk(i)
                for x in visited:
                    control[x] = 0
                if flag:
                    return True, list_circle
        # Didn't find any circle in all rounds.
        return False, list_circle


if __name__ == "__main__":
    line = input().split()
    V, E = int(line[0]), int(line[1])
    # Initialize the graph
    g = Graph(V)
    for r in range(E):
        row = input().split()
        start, end = int(row[0])-1, int(row[1])-1
        g.add_edge(start, end)

    flag, list_circle = g.is_cyclic()
    if flag:
        print("YES")
        print(" ".join(str(i+1) for i in list_circle))
    else:
        print("NO")

第一行是頂點數和邊數。 在第一行之后,每條線代表一條邊(有向)。

輸入:

3 3

1 2

2 3

3 1

輸出:

1 2 3

我會說這段代碼效率不是很高。 為什么您有list_circle並以不同的方式visited 同樣將它們存儲為list意味着v in list_circle檢查中的v in list_circle需要O(n)所以整個算法可能是O(n^2) 我認為對您來說,一個不好的例子是“ P”,但循環很小,行很長,您從該行的底部開始,因此您必須遍歷整個行,直到最終找到循環為止。

我懷疑如果將它們合並到單個dict()以將DFS結果存儲為

visited[child] = parent

很難為此創建一個不好的案例,並且您仍然可以通過從第一個雙重訪問的點沿兩種方式返回,輕松地根據該信息重新構造一個循環。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM