【问题标题】:Optimizing the algorithm of detecting cycle in a graph using python使用python优化检测图中循环的算法
【发布时间】:2019-01-25 00:50:46
【问题描述】:

我已经实现了这段代码,使用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

【问题讨论】:

  • 如果代码正确,但只需要性能改进,应该在 Code Review 上,而不是在这里。请注意,尽管它们需要工作的完整代码。
  • 你在这里有点重新发明轮子。您对使用图形库的解决方案感兴趣吗?
  • @wim 这是 OJ 任务,不允许使用库

标签: python algorithm graph


【解决方案1】:

我想说这段代码不是很低效。为什么你有 list_circlevisited 作为不同的东西?同样将它们存储为list 意味着v in list_circle 检查采用O(n),因此整个算法可能是O(n^2)。我认为对你来说一个不好的例子是像“P”这样的东西,但是有一个非常小的循环和一条很长的线,你从那条线的底部开始,所以你必须走整条线,直到你最终找到循环。

我怀疑如果您将它们合并为一个 dict() 以将您的 DFS 结果存储为

visited[child] = parent

很难为它创建一个坏案例,您仍然可以通过从第一个双重访问点沿两条路径返回,轻松地根据该信息重新构建一个循环。

【讨论】:

    猜你喜欢
    • 2021-05-04
    • 2010-10-26
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多