[BOJ] 4386 별자리 만들기
크루스칼
이 문제는 정점이 좌표로 이루어져 있다. 이를 통해 최소 신장 트리를 구현해야 한다. 보통 기본 유형은 노드 번호가 주어지고 노드간 거리가 주어지면 kruskal을 이용해서 최소 신장 트리를 구할 수 있었다.
다른 문제에 비해 까다로운 포인트
- 부동 소수점으로 주어지는 input
- 노드 번호가 아니라 좌표로 주어지는점
- 소수점 둘째 자리에서 반올림 하는 점
위 세가지 까다로운 포인트를 해결하기 위해 우선 입력받은 좌표를 노드 번호로 맵핑해준다(2번 해결). 그리고 부동 소수점을 해결하기 위해서는 . ← 을 파싱해주는 방법과 그냥 map(float)
를 해버리는 방법이 있다. 나는 후자로 구현했다. 이건 문제에서 주어지는 인풋 형식에 따라 다를 테니 그때그때 상황에 맞춰서 해야 한다. 마지막으로 둘째 자리에서 반올림 하는 것은 허용 오차가 주어진다. 10^-2임을 보아 그냥 round를 사용하면 될듯 하다.
따라서 위와 같은 까다로운 포인트를 통해 좌표계로 주어진 점은 기존 우리가 kruskal을 구현할 떄 사용하는 거리-노드번호 형태의 배열로 구현한 뒤 편하게 kruskal을 사용하면 된다. 코드는 아래와 같다.
구현
import sys
def find(x, parent):
if x != parent[x]:
parent[x] = find(parent[x], parent)
return parent[x]
def union(a, b, parent):
a = find(a, parent)
b = find(b, parent)
if a < b:
parent[b] = a
else:
parent[a] = b
return parent
def get_distance(x1, y1, x2, y2):
return round(((x1 - x2)**2 + (y1 - y2)**2)**0.5, 2)
def solution():
edges = []
for i in range(len(points)):
for j in range(i+1, len(points)):
dist = get_distance(points[i][0], points[i][1], points[j][0], points[j][1])
edges.append([dist, points[i][2], points[j][2]])
edges.sort()
parent = [i for i in range(len(points))]
answer = 0
for dist, a, b in edges:
if find(a, parent) == find(b, parent):
continue
parent = union(a, b, parent)
answer += dist
return answer
if __name__ == "__main__":
N = int(sys.stdin.readline().rstrip())
points = []
for Idx in range(N):
A, B = map(float, sys.stdin.readline().rstrip().split())
points.append([A, B, Idx])
print(solution())