python 3.x - Finding cycle in graph. Why getting wrong results? - Stack Overflow

I am looking at GeeksforGeeks problem Cycle in a Directed Graph:Given a Directed Graph with V vertices

I am looking at GeeksforGeeks problem Cycle in a Directed Graph:

Given a Directed Graph with V vertices (Numbered from 0 to V−1) and E edges, check whether it contains any cycle or not.

The graph is represented as an adjacency list, where adj[i] contains a list of vertices that are directly reachable from vertex i. Specifically, adj[i][j] represents an edge from vertex i to vertex j.

Example 1:

Output: 1

Explanation: 3 -> 3 is a cycle.

My code

from typing import List

class Solution:
    
    # Function to detect cycle in a directed graph.
    def is_cyclic(self, adj : List[List[int]]) -> bool :
        def dfs(i, arr):
            vis[i] = 1
            for item in adj[i]:
                if not vis[item]:
                    arr.append(i)
                    if dfs(item,arr) == True:return True
                    arr.pop()
                else:
                    if item in arr:
                        return True
        n = len(adj)
        vis = [0]*n
        for i in range(n):
            if not vis[i]:
                if dfs(i,[i]) == True:
                    return True
        return False     

But this gives False for the example input while True is expected.

I changed the approach as to where to append nodes to the path arr like below, and then it worked, but I don't see why the above code wouldn't return the exact same results:

from typing import List

class Solution:
    
    # Function to detect cycle in a directed graph.
    def is_cyclic(self, adj : List[List[int]]) -> bool :
        def dfs(i, arr):
            vis[i] = 1
            arr.append(i)
            for item in adj[i]:
                if not vis[item]:
                    if dfs(item,arr) == True:
                        return True
                else:
                    if item in arr:
                        return True 
            arr.pop()
        n = len(adj)
        vis = [0]*n
        for i in range(n):
            if not vis[i]:
                if dfs(i,[]) == True:
                    return True
        return False    

The difference is only in the list that is passed to dfs. I don't understand why my code does not work properly as it essentially uses the same logic. What is my mistake?

I am looking at GeeksforGeeks problem Cycle in a Directed Graph:

Given a Directed Graph with V vertices (Numbered from 0 to V−1) and E edges, check whether it contains any cycle or not.

The graph is represented as an adjacency list, where adj[i] contains a list of vertices that are directly reachable from vertex i. Specifically, adj[i][j] represents an edge from vertex i to vertex j.

Example 1:

Output: 1

Explanation: 3 -> 3 is a cycle.

My code

from typing import List

class Solution:
    
    # Function to detect cycle in a directed graph.
    def is_cyclic(self, adj : List[List[int]]) -> bool :
        def dfs(i, arr):
            vis[i] = 1
            for item in adj[i]:
                if not vis[item]:
                    arr.append(i)
                    if dfs(item,arr) == True:return True
                    arr.pop()
                else:
                    if item in arr:
                        return True
        n = len(adj)
        vis = [0]*n
        for i in range(n):
            if not vis[i]:
                if dfs(i,[i]) == True:
                    return True
        return False     

But this gives False for the example input while True is expected.

I changed the approach as to where to append nodes to the path arr like below, and then it worked, but I don't see why the above code wouldn't return the exact same results:

from typing import List

class Solution:
    
    # Function to detect cycle in a directed graph.
    def is_cyclic(self, adj : List[List[int]]) -> bool :
        def dfs(i, arr):
            vis[i] = 1
            arr.append(i)
            for item in adj[i]:
                if not vis[item]:
                    if dfs(item,arr) == True:
                        return True
                else:
                    if item in arr:
                        return True 
            arr.pop()
        n = len(adj)
        vis = [0]*n
        for i in range(n):
            if not vis[i]:
                if dfs(i,[]) == True:
                    return True
        return False    

The difference is only in the list that is passed to dfs. I don't understand why my code does not work properly as it essentially uses the same logic. What is my mistake?

Share Improve this question edited Mar 11 at 22:48 daqh 1461 silver badge12 bronze badges asked Mar 8 at 10:08 SwastikSwastik 133 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

You are right in your general idea that it shouldn't matter whether you add the node to arr either at the start of dfs or just before dfs is called (and when in both cases you remove that node from arr again when that call returns without success).

However, you did not add the correct node in the version that fails the test.

In the first (failing) version, the node that should be added in the for loop should be the adjacent node being iterated, not i. So change this:

        for item in adj[i]:
            if not vis[item]:
                arr.append(i)  # <-- wrong node!

to this:

        for item in adj[i]:
            if not vis[item]:
                arr.append(item)  # <-- correct node

...and now also the first version of your code will work as expected.

Other remarks

Unrelated to your question, but evaluating the condition item in arr is not efficient. You could reduce the execution time for this condition by using vis for this purpose: use value 1 to indicate that the node is on the current path, and 2 that it is also visited, but no longer on the current path.

Also, you can make use of map and any to make your loops implicit. This results in this variant:

    def isCyclic(self, adj: List[List[int]]) -> bool:
        def dfs(i):
            if vis[i] == 1:
                return True
            vis[i] = 1
            if any(map(dfs, adj[i])):
                return True
            vis[i] = 2

        n = len(adj)
        vis = [0] * n
        return any(map(dfs, range(n)))

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744898819a4599854.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信