안녕하세요, 여러분! 이번 글에서는 파이썬을 이용하여 코딩 테스트에서 자주 다루어지는 알고리즘 문제를 해결하는 방법에 대해 알아보겠습니다. 주제는 ‘다리 만들기’입니다. ‘다리 만들기’ 문제는 실제로 다양한 변형이 존재하는 classic 문제로, 그래프 이론과 관련한 중요한 개념들을 포함하고 있습니다.
문제 설명
주어진 여러 개의 섬이 있습니다. 각 섬은 서로 다른 위치에 있으며, 섬들 간에 다리를 건설하려고 합니다. 이때, 다리는 수직 또는 수평으로만 건설할 수 있으며, 다리가 직선으로 뻗어나가야 합니다. 또한, 가능한 한 많은 섬을 연결할 수 있도록 다리의 총 길이를 최소화해야 합니다.
주어진 섬의 좌표가 x, y로 주어질 때, 최소 다리의 총 길이를 출력하는 함수를 작성하세요.
def minimum_bridge_length(islands: List[Tuple[int, int]]) -> int:
pass
입력
섬의 개수 N(2 ≤ N ≤ 10,000)과 각 섬의 좌표 (x, y) 리스트가 주어집니다.
출력
최소 다리의 총 길이를 정수로 반환합니다.
문제 풀이 과정
1. 문제 이해하기
문제의 목표는 주어진 여러 개의 섬을 연결하는 최소 다리의 총 길이를 찾는 것입니다. 이 문제의 핵심은 각 섬 사이의 다리 길이가 어떻게 계산되는지를 이해하는 것입니다. 두 섬의 좌표 (x1, y1)와 (x2, y2)가 있을 때, 이들 사이의 다리 길이는 |x1 – x2| + |y1 – y2|로 계산될 수 있습니다. 즉, 각 섬의 x좌표와 y좌표의 차이를 합한 값입니다.
2. 알고리즘 설계
섬들 간의 모든 조합을 고려하여 다리를 건설하는 방식으로 문제를 해결할 수 있습니다. 그러나 N이 최대 10,000이므로 모든 조합을 고려하면 O(N^2) 시간 복잡도를 가지게 되어 효율적이지 않습니다. 대신, 최소 신장 트리(MST) 알고리즘을 활용하여 다리를 최소한으로 연결할 수 있도록 합니다.
MST를 구성하기 위해 Kruskal 또는 Prim 알고리즘을 사용할 수 있습니다. 여기서는 Prim 알고리즘을 사용할 것입니다. 이 알고리즘은 그래프의 한 꼭짓점에서 시작하여 가장 짧은 간선을 하나씩 추가해가며 최소 신장 트리를 만드는 방식입니다.
3. Prim 알고리즘 구현
먼저, 각 섬의 좌표를 저장하는 리스트와 연결 비용을 저장하는 우선순위 큐를 준비합니다. 그런 다음, 한 섬에서 시작하여 연결된 모든 섬의 다리 길이를 계산하고, 가장 짧은 길이의 섬을 추가하는 과정을 반복합니다.
import heapq
from typing import List, Tuple
def minimum_bridge_length(islands: List[Tuple[int, int]]) -> int:
n = len(islands)
visited = [False] * n
min_heap = []
# 첫 번째 섬에서 시작
for i in range(1, n):
dist = abs(islands[0][0] - islands[i][0]) + abs(islands[0][1] - islands[i][1])
heapq.heappush(min_heap, (dist, i))
visited[0] = True
total_length = 0
edges_used = 0
while min_heap and edges_used < n - 1:
dist, island_index = heapq.heappop(min_heap)
if visited[island_index]:
continue
visited[island_index] = True
total_length += dist
edges_used += 1
for i in range(n):
if not visited[i]:
new_dist = abs(islands[island_index][0] - islands[i][0]) + abs(islands[island_index][1] - islands[i][1])
heapq.heappush(min_heap, (new_dist, i))
return total_length
4. 복잡도 분석
이 알고리즘의 시간 복잡도는 O(E log V)입니다. 여기서 E는 간선의 개수이고 V는 정점의 개수입니다. 하지만 모든 조합을 고려하지 않고 각 섬을 기준으로 다리를 생성하기 때문에, 실질적인 성능은 더 우수합니다.
5. 예제
이제 이 알고리즘을 사용하여 예제를 해결해 보겠습니다.
islands = [(0, 0), (1, 1), (3, 1), (4, 0)]
print(minimum_bridge_length(islands)) # Output: 4
위 예제에서, (0,0)에서 (1,1)의 다리, (1,1)에서 (3,1), 그리고 (3,1)에서 (4,0)까지 연결할 수 있습니다. 총 다리 길이는 4가 됩니다.