1
- from collections import defaultdict , deque
1
+ from queue import Queue
2
+ from collections import defaultdict
2
3
3
- def is_bipartite_dfs (graph : defaultdict [int , list [int ]]) -> bool :
4
+ def check_bipartite (graph : dict [int , list [int ]])-> bool :
4
5
"""
5
- Check graph bipartite using DFS .
6
+ Check graph bipartite using BFS .
6
7
7
8
Args:
8
- graph (defaultdict [int, list [int]]): Adjacency list.
9
+ graph (dict [int, List [int]]): Adjacency list.
9
10
10
11
Returns:
11
12
bool: True if bipartite, False otherwise.
12
13
13
14
Divides graph into two sets without same-set connections.
14
15
15
16
Examples:
16
- >>> is_bipartite_dfs(defaultdict (list, {0: [1, 2], 1: [0, 3], 2: [0, 4]}))
17
+ >>> check_bipartite(dict (list, {0: [1, 2], 1: [0, 3], 2: [0, 4]}))
17
18
True
18
- >>> is_bipartite_dfs(defaultdict (list, {0: [1, 2], 1: [0, 2], 2: [0, 1]}))
19
+ >>> check_bipartite(dict (list, {0: [1, 2], 1: [0, 2], 2: [0, 1]}))
19
20
False
20
21
"""
21
- def dfs (node , color ):
22
- """
23
- DFS starting from a node.
24
-
25
- Args:
26
- node: Current node.
27
- color: Color assigned to the current node.
22
+ queue :Queue () = Queue ()
23
+ visited = [False ] * len (graph )
24
+ color = [- 1 ] * len (graph )
28
25
29
- Returns:
30
- bool: True if bipartite starting from the current node.
26
+ def bfs ()-> bool :
27
+ while not queue .empty ():
28
+ u = queue .get ()
29
+ visited [u ] = True
31
30
32
- Examples:
33
- >>> dfs(0, 0, defaultdict(list, {0: [1, 2], 1: [0, 3], 2: [0, 4]}))
34
- True
35
- >>> dfs(0, 0, defaultdict(list, {0: [1, 2], 1: [0, 2], 2: [0, 1]}))
36
- False
37
- """
38
- if visited [node ] == - 1 :
39
- visited [node ] = color
40
- for neighbor in graph [node ]:
41
- if not dfs (neighbor , 1 - color ):
31
+ for neighbour in graph [u ]:
32
+ if neighbour == u :
42
33
return False
43
- return visited [node ] == color
44
34
45
- visited = defaultdict (lambda : - 1 )
46
- for node in graph :
47
- if visited [node ] == - 1 and not dfs (node , 0 ):
48
- return False
49
- return True
35
+ if color [neighbour ] == - 1 :
36
+ color [neighbour ] = 1 - color [u ]
37
+ queue .put (neighbour )
50
38
51
- def is_bipartite_bfs (graph : defaultdict [int , list [int ]]) -> bool :
39
+ elif color [neighbour ] == color [u ]:
40
+ return False
41
+ return True
42
+
43
+ for i in range (len (graph )):
44
+ if not visited [i ]:
45
+ queue .put (i )
46
+ color [i ] = 0
47
+ if bfs () is False :
48
+ return False
49
+ return True
50
+ def is_bipartite (graph : defaultdict [int , list [int ]]) -> bool :
52
51
"""
53
- Check graph bipartite using BFS.
52
+ Check whether a graph is Bipartite or not using Depth-First Search (DFS).
53
+
54
+ A Bipartite Graph is a graph whose vertices can be divided into two independent
55
+ sets, U and V such that every edge (u, v) either connects a vertex from
56
+ U to V or a vertex from V to U. In other words, for every edge (u, v),
57
+ either u belongs to U and v to V, or u belongs to V and v to U. There is
58
+ no edge that connects vertices of the same set.
54
59
55
60
Args:
56
- graph (defaultdict[int, list[int]]): Adjacency list .
61
+ graph: An adjacency list representing the graph .
57
62
58
63
Returns:
59
- bool: True if bipartite, False otherwise.
60
-
61
- Divides graph into two sets without same-set connections.
64
+ True if there's no edge that connects vertices of the same set, False otherwise.
62
65
63
66
Examples:
64
- >>> is_bipartite_bfs(defaultdict(list, {0: [1, 2], 1: [0, 3], 2: [0, 4]}))
65
- True
66
- >>> is_bipartite_bfs(defaultdict(list, {0: [1, 2], 1: [0, 2], 2: [0, 1]}))
67
- False
67
+ >>> is_bipartite(
68
+ ... defaultdict(list, {0: [1, 2], 1: [0, 3], 2: [0, 4], 3: [1], 4: [2]})
69
+ ... )
70
+ False
71
+ >>> is_bipartite(defaultdict(list, {0: [1, 2], 1: [0, 2], 2: [0, 1]}))
72
+ True
68
73
"""
69
- visited = defaultdict (lambda : - 1 )
70
- for node in graph :
71
- if visited [node ] == - 1 :
72
- queue = deque ()
73
- queue .append (node )
74
- visited [node ] = 0
75
- while queue :
76
- curr_node = queue .popleft ()
77
- for neighbor in graph [curr_node ]:
78
- if visited [neighbor ] == - 1 :
79
- visited [neighbor ] = 1 - visited [curr_node ]
80
- queue .append (neighbor )
81
- elif visited [neighbor ] == visited [curr_node ]:
82
- return False
83
- return True
84
74
85
- if __name__ == "__main" :
75
+ def depth_first_search (node : int , color : int ) -> bool :
76
+ visited [node ] = color
77
+ return any (
78
+ visited [neighbour ] == color
79
+ or (
80
+ visited [neighbour ] == - 1
81
+ and not depth_first_search (neighbour , 1 - color )
82
+ )
83
+ for neighbour in graph [node ]
84
+ )
85
+
86
+ visited : defaultdict [int , int ] = defaultdict (lambda : - 1 )
87
+
88
+ return all (
89
+ not (visited [node ] == - 1 and not depth_first_search (node , 0 )) for node in graph
90
+ )
91
+
92
+
93
+ if __name__ == "__main__" :
86
94
import doctest
87
95
88
96
result = doctest .testmod ()
89
97
90
98
if result .failed :
91
99
print (f"{ result .failed } test(s) failed." )
92
100
else :
93
- print ("All tests passed!" )
101
+ print ("All tests passed!" )
0 commit comments