class Graph:
def __init__(self, edges):
self.adj = {}
for u, v in edges:
self.adj.setdefault(u, []).append(v)
self.adj.setdefault(v, []).append(u)
def has_cycle_util(self, node, visited, parent):
visited.add(node)
for neighbor in self.adj.get(node, []):
if neighbor not in visited:
if self.has_cycle_util(neighbor, visited, node):
return True
elif neighbor != parent:
return True
return False
def has_cycle(self):
visited = set()
for node in self.adj:
if node not in visited:
if self.has_cycle_util(node, visited, None):
return True
return False
class Tree(Graph):
def __init__(self, edges):
super().__init__(edges)
def is_tree(self):
# Tree has no cycles and is connected
if self.has_cycle():
return False
visited = set()
def dfs(node):
visited.add(node)
for neighbor in self.adj.get(node, []):
if neighbor not in visited:
dfs(neighbor)
start = next(iter(self.adj)) if self.adj else None
if start is None:
return True # empty tree
dfs(start)
return len(visited) == len(self.adj)
# Driver code
# Graph with cycle
graph_edges = [(1,2), (2,4), (4,3), (3,1)]
graph = Graph(graph_edges)
print("Graph has cycle:", graph.has_cycle())
# Tree without cycle
tree_edges = [(1,2), (1,3)]
tree = Tree(tree_edges)
print("Tree is valid:", tree.is_tree())for u, v in edges:
self.adj.setdefault(u, []).append(v)
self.adj.setdefault(v, []).append(u)
Build adjacency list for undirected graph
Mark current node as visited
for neighbor in self.adj.get(node, []):
Check all neighbors of current node
if neighbor not in visited:
if self.has_cycle_util(neighbor, visited, node):
return True
Recursively visit unvisited neighbors to detect cycle
elif neighbor != parent:
return True
If neighbor visited and not parent, cycle detected
if self.has_cycle():
return False
If cycle found, not a tree
dfs(start)
return len(visited) == len(self.adj)
Check connectivity: all nodes must be visited
Graph has cycle: True
Tree is valid: True