https://school.programmers.co.kr/learn/courses/30/lessons/86971
This was similiar to [Programmers] 네트워크 problem so I tried solving it through dfs where I remove that wire from graph and do dfs search on that modified graph.
my wrong code:
from collections import deque,defaultdict
import math
def solution(n, wires):
graph = defaultdict(list)
for wire in wires:
graph[wire[0]].append(wire[1])
graph[wire[1]].append(wire[0])
print(graph)
visited = [False for _ in range(n+1)]
count =n
for wire in wires:
graph[wire[0]].remove(wire[1])
graph[wire[1]].remove(wire[0])
for i in range(1,len(graph)+1):
if not visited[i] and graph[i]:
count = min(count, dfs(visited, graph, i))
# Restore the removed edges
graph[wire[0]].append(wire[1])
graph[wire[1]].append(wire[0])
print(count)
return count
def dfs(visited,graph,i):
visited[i]=True
count=1
for next_node in graph[i]:
if not visited[next_node]:
count += dfs(visited,graph,next_node)
return count
But the problem is that removing wire from my graph resulted in empty list for a given key and dfs still traverses through that. So that is the wrong part. I needed a different way to mark the disconnection, apart from this remove() way.
Also another problem was using the same visited list each time I iterated through wires. I should have instantiated a new one each time for each wire.
For the first problem, I googled and some used a 2d list like this check_link. (or you can create graph each time you iterate through wires but inefficient)
# 없앤 간선인지 아닌지 체크 값이 들어있는 리스트
check_link = [[True]*(n+1) for _ in range(n+1)]
for a, b in wires:
visited = [False]*(n+1)
check_link[a][b] = False # a-b 간선 끊기
cnt_a = DFS(a, graph, visited, check_link)
cnt_b = DFS(b, graph, visited, check_link)
check_link[a][b] = True # a-b 간선 다시 연결
This check_link will check if there is a disconnection from a to b, which will be marked as False if there is a disconnection. And in our DFS search, we only proceed deeper if
We do 2 DFS search - 1 from a and 1 from b. During DFS, we will be using the same visited list and marking some nodes as visited. If the other DFS search stumbles upon an already visited node or if it is not visited but the connection to that point from current node is False (disconnected) then we can't visit that node and increment count.
And importantly, once we finish our DFS search, we have to connect the disconnection back (from False to True).
from collections import defaultdict
def solution(n, wires):
ans = int(10e9)
graph = defaultdict(list)
for wire in wires:
graph[wire[0]].append(wire[1])
graph[wire[1]].append(wire[0])
check_link = [[True for _ in range(n+1)] for _ in range(n+1)]
def dfs(i,visited):
visited[i]=True
count =1
for node in graph[i]:
if not visited[node] and check_link[i][node]:
count += dfs(node,visited)
return count
for wire in wires:
visited=[False for _ in range(n+1)]
check_link[wire[0]][wire[1]]=False
count1 = dfs(wire[0],visited)
count2 = dfs(wire[1],visited)
check_link[wire[0]][wire[1]]=True
ans = min(abs(count1-count2),ans)
return ans
Or you can make it more nice by taking dfs function outside
def solution(n, wires):
graph = defaultdict(list)
for wire in wires:
graph[wire[0]].append(wire[1])
graph[wire[1]].append(wire[0])
print(graph)
check_link = [[True for _ in range(n+1)] for _ in range(n+1)]
count = n
for wire in wires:
visited = [False for _ in range(n+1)]
check_link[wire[0]][wire[1]] = False
count1= dfs(visited,check_link,graph,wire[0])
count2=dfs(visited,check_link,graph,wire[1])
count = min(abs(count1-count2),count)
# Restore the removed edges
check_link[wire[0]][wire[1]] = True
print(count)
return count
def dfs(visited,check_link,graph,node):
visited[node]=True
count=1
for next_node in graph[node]:
if not visited[next_node] and check_link[node][next_node]:
count += dfs(visited,check_link, graph,next_node)
return count
revisited [13th jan] well-explained by me
The time complexity of this solution is O(N^2), and the space complexity is O(N^2), where N is the number of nodes or vertices in the graph.
Here's a breakdown of the complexities:
Time Complexity (O(N^2)):
graph
dictionary by iterating through wires
takes O(N) time because there are at most N edges.wires
, so it can be called at most N times.Space Complexity (O(N^2)):
graph
dictionary stores adjacency lists for each node, and in the worst case, where all nodes are connected to each other, it will have O(N^2) entries.check_link
matrix also has N^2 elements.So, both time and space complexities are quadratic in terms of the number of nodes (N).