[Python] [BOJ] 우주신과의 교감(1774)

긍정왕·2021년 6월 26일
1

Algorithm

목록 보기
33/69

💡 문제 해결

Prim's Algorithm

  1. 노드의 방문 여부를 나타낼 visited와 간선 정보를 담을 graph생성
  2. 각 노드간 연결될 수 있는 간선의 길이 정보를 저장
  3. 이미 연결되어 있는 간선의 가중치는 0으로 전환
  4. 한 점에서 출발하여 heapq를 활용해 연결
  5. 현재 노드와 연결된 가장 짧은 가중치를 갖는 간선을 선택하여 해당 노드로 이동
  6. 이동하며 더한 가중치를 소수점 2번째 자리까지 출력

Kruskal's Algorithm

  1. 신들의 좌표값을 idx의 값에 맞춰 1번부터 저장
  2. 각 번호에 해당하는 신들의 루트노드를 본인번호를 기본값으로 하는 parent 리스트 생성
  3. 각 번호에 해당하는 신들의 높이를 나타내줄 rank 리스트 생성
  4. 모든 간선의 정보를 heap 리스트에 저장
  5. 가장 작은 가중치를 갖는 간선부터 pop하며 parentrank를 갱신
  6. union-find 알고리즘을 통해 연결 여부를 파악
  7. 더해진 가중치를 소수점 2번째 자리까지 출력

📌 MST의 두가지 알고리즘에 대해 연습하기 좋은 문제
📌 해당 알고리즘에 대한 자세한 설명은 MST 알고리즘에 대한 정리를 참고



🧾 문제 설명

황선자씨는 우주신과 교감을 할수 있는 채널러 이다. 
하지만 우주신은 하나만 있는 것이 아니기때문에 황선자 씨는 매번 여럿의 우주신과 교감하느라 힘이 든다. 
이러던 와중에 새로운 우주신들이 황선자씨를 이용하게 되었다.

하지만 위대한 우주신들은 바로 황선자씨와 연결될 필요가 없다. 
이미 황선자씨와 혹은 이미 우주신끼리 교감할 수 있는 우주신들이 있기 때문에 
새로운 우주신들은 그 우주신들을 거쳐서 황선자 씨와 교감을 할 수 있다.

우주신들과의 교감은 우주신들과 황선자씨 혹은 우주신들 끼리 이어진 정신적인 통로를 통해 이루어 진다. 
하지만 우주신들과 교감하는 것은 힘든 일이기 때문에 황선자씨는 이런 통로들이 긴 것을  좋아하지 않는다. 
왜냐하면 통로들이 길 수록 더 힘이 들기 때문이다.

또한 우리들은 3차원 좌표계로 나타낼 수 있는 세상에 살고 있지만 
우주신들과 황선자씨는 2차원 좌표계로 나타낼 수 있는 세상에 살고 있다. 
통로들의 길이는 2차원 좌표계상의 거리와 같다.

이미 황선자씨와 연결된, 혹은 우주신들과 연결된 통로들이 존재한다. 
우리는 황선자 씨를 도와 아직 연결이 되지 않은 우주신들을 연결해 드려야 한다. 
새로 만들어야 할 정신적인 통로의 길이들이 합이 최소가 되게 통로를 만들어 “빵상”을 외칠수 있게 도와주자.

문제보기



🖨 입출력



📝 풀이

- Prim's Algorithm

import heapq

N, M = map(int, input().split())

node = [list(map(int, input().split())) for _ in range(N)]
visited = [False] * N
graph = [[0] * N for _ in range(N)]

for i in range(N):
    for j in range(i+1, N):
        dis = (node[i][0] - node[j][0]) ** 2 + (node[i][1] - node[j][1]) ** 2
        dis = dis ** 0.5
        graph[i][j] = dis
        graph[j][i] = dis

for i in range(M):
    a, b = map(int, input().split())
    graph[a - 1][b - 1] = 0
    graph[b - 1][a - 1] = 0


heap = [[0, 0]]
answer = 0
for i in range(N):
    while heap:
        cost, idx = heapq.heappop(heap)
        if visited[idx]:
            continue
        for i in range(N):
            if not visited[i]:
                heapq.heappush(heap, [graph[idx][i], i])
        visited[idx] = True
        answer += cost
        break

print(f'{answer:.2f}')

- Kruskal Algorithm

import sys, heapq

input = sys.stdin.readline

def find(x):
    if parent[x] == x: return x

    parent[x] = find(parent[x])
    return parent[x]


def union(x, y):
    x, y = find(x), find(y)

    if x == y: return False

    if rank[x] < rank[y]:
        x, y = y, x

    parent[y] = x

    if rank[x] == rank[y]:
        rank[y] += 1
    return True



N, M = map(int, input().split())
points = [0] + [list(map(int, input().split())) for _ in range(N)]
parent = [i for i in range(N + 1)]
rank = [1] * (N + 1)
for _ in range(M):
    union(*map(int, input().split()))

heap = []
for i in range(1, N):
    for j in range(i + 1, N + 1):
        dis = (abs(points[i][0] - points[j][0]) ** 2 + abs(points[i][1] - points[j][1]) ** 2) ** 0.5
        heapq.heappush(heap, (dis, i, j))

answer = 0
while heap:
    cost, start, end = heapq.heappop(heap)

    if union(start, end):
        answer += cost

print(f'{answer:.2f}')

profile
Impossible + 땀 한방울 == I'm possible

0개의 댓글