import sys
import heapq
def input():
return sys.stdin.readline().rstrip()
def find_parents(X):
if X == make_set[X]:
return X
make_set[X] = find_parents(make_set[X])
return make_set[X]
def union(x,y):
X = find_parents(x)
Y = find_parents(y)
if X !=Y:
if ranks[X]< ranks[Y]:
X,Y = Y,X
make_set[Y] = X
if ranks[X] == ranks[Y]:
ranks[X] += 1
return True
return False
N,M = map(int,input().split())
edge_list = []
for x in range(N):
temp = list(input())
for y in range(x+1,N):
if temp[y] == 'Y':
heapq.heappush(edge_list,(x,y))
city_cnt = 0
if len(edge_list) >= M:
result = [0 for _ in range(N)]
make_set = [i for i in range(N)]
ranks = [1 for _ in range(N)]
remain_list = []
while edge_list:
node_a,node_b = heapq.heappop(edge_list)
if union(node_a,node_b):
city_cnt += 1
result[node_b] += 1
result[node_a] += 1
else:
heapq.heappush(remain_list,(node_a,node_b))
if city_cnt != N-1:
print(-1)
else:
remain_cnt = M - city_cnt
while remain_cnt>0:
node_a,node_b = heapq.heappop(remain_list)
result[node_a] += 1
result[node_b] += 1
remain_cnt -= 1
print(*result)
else:
print(-1)
이 문제는 문제를 이해하는데 힘들었고, 구현을 하는데 어려운 점이 많았었다.
평소에 MST 관련 문제는 프림 알고리즘을 주로 이용해서 풀었지만, 이 문제를 푸는데에는 크루스칼 알고리즘을 이용했다.
문제를 푸는 방식은 다음과 같다. 모든 간선들을 저장을 해주는데, 그 조건은 x,y 에서 y는 무조건 x보다 큰 경우의 간선만 저장을 시켜준다.
그래서 모든 간선을 저장시켰는데 주어진 M보다 적을때에는 -1을 출력을 해준다.
그리고 크루스칼 알고리즘을 이용해서 풀면된다.
그러나, 여기서 다른 점은 우리가 이미 union이 된 간선들을 버리게 되는데, 이걸 따로 저장을 시켜놓는다.
그리고 우리는 모든 크루스칼 알고리즘을 돌린뒤에, 모든 도시가 연결이 안되어있으면 -1을 출력을 해주고,
그리고 우리는 무조건 도로 M개를 무조건 연결을 해야하므로, 우리는 크루스칼 알고리즘을 통해 N-1개를 연결을 해놓은 상태이다.
그러므로 M-(N-1)개의 도로를 추가적으로 연결을 시켜주면 된다.
그래서 우리는 저장시켜놓은 도로들을 우선순위가 높은 것부터 뽑아서 연결을 시켜주면 된다.
import sys
from collections import deque
def input():
return sys.stdin.readline().rstrip()
def find_parents(X):
if X == make_set[X]:
return X
make_set[X] = find_parents(make_set[X])
return make_set[X]
def union(x,y):
X = find_parents(x)
Y = find_parents(y)
if X !=Y:
if ranks[X]< ranks[Y]:
X,Y = Y,X
make_set[Y] = X
if ranks[X] == ranks[Y]:
ranks[X] += 1
return True
return False
N,M = map(int,input().split())
edge_list = deque()
result = [0 for _ in range(N)]
make_set = [i for i in range(N)]
ranks = [1 for _ in range(N)]
city_cnt = 0
for x in range(N):
temp = list(input())
for y in range(x+1,N):
if temp[y] == 'Y':
if union(x,y):
city_cnt += 1
result[x] += 1
result[y] += 1
else:
edge_list.append((x,y))
if city_cnt<N-1 or city_cnt+len(edge_list)<M:
print(-1)
else:
remain_cnt = M - city_cnt
while remain_cnt>0:
x,y = edge_list.popleft()
result[x] += 1
result[y] += 1
remain_cnt -= 1
print(*result)
이건 코드를 좀 더 개선시킨 버전이다.
달라진것은 heapq 대신 그냥 앞에서부터 차근차근 해주는 방식으로 바꿔준 것이다.
이 문제는 크루스칼을 이용하는 것뿐만 아니라, 문제를 잘 분석해야 풀 수 있었떤 문제였다.
'알고리즘 > 백준' 카테고리의 다른 글
[BOJ/백준] 2463 비용 (0) | 2021.06.29 |
---|---|
[BOJ/백준] 1398 동전 (0) | 2021.06.29 |
[BOJ/백준] 2250 트리의 높이와 너비 (0) | 2021.06.22 |
[BOJ/백준] 2213 트리의 독립집합 (0) | 2021.06.22 |
[BOJ/백준] 1414 불우이웃 돕기 (0) | 2021.06.22 |