def dfs(V, parent, flag, vis, adj):
# Mark visited
vis[V] = 1
# Iterating over V's neighbors
for U in adj[V]:
# If U is not visited
if not vis[U]:
# Call dfs function for node U
# with parent V
dfs(U, V, flag, vis, adj)
# If U is already visited and it is
# not the last node that we visited
# then there is a loop in connected
# components so mark flag as 1
elif U != parent and parent != -1:
flag[0] = 1
def findMinMaxCC(A, N):
# Creating adjacency list
adj = [[] for _ in range(N + 1)]
# Filling adjacency list
for i in range(N):
# There is an undirected edge
# from i to A[i]
adj[i + 1].append(A[i])
adj[A[i]].append(i + 1)
# Counters for looped and without looped
# connected components
loopConnectedComponents = 0
withoutLoopConnectedComponents = 0
# Creating visited array for dfs
vis = [0] * (N + 1)
# Flag to check if the given connected
# component has a loop
flag = [0]
# Iterating for all N nodes
for i in range(1, N + 1):
# If node i is not visited, call dfs
# for that node
if not vis[i]:
# Call dfs function
dfs(i, -1, flag, vis, adj)
# If flag is true, increment looped
# Connected component counter by 1
if flag[0]:
loopConnectedComponents += 1
# If not, increment without looped
# connected components counter by 1
else:
withoutLoopConnectedComponents += 1
# Resetting the flag
flag[0] = 0
# Maximum connected components
maxConnectedComponents = (
loopConnectedComponents + withoutLoopConnectedComponents
)
# Minimum connected components
minConnectedComponents = loopConnectedComponents
# Unify all connected components which
# do not have a loop as 1 connected component
if withoutLoopConnectedComponents != 0:
minConnectedComponents += 1
# Printing answer of minimum and maximum
# connected components
print(minConnectedComponents, maxConnectedComponents)
# Driver Code
if __name__ == "__main__":
# Input 1
A = [2, 1, 4, 3, 6, 5]
N = 6
# Function Call
findMinMaxCC(A, N)
# Input 2
A1 = [2, 3, 1, 5, 6, 4]
N1 = 6
# Function Call
findMinMaxCC(A1, N1)