[KR] 백준 33527 - 신촌 길찾기 서비스
백준 33527 - 신촌 길찾기 서비스
해당 문제는 BFS로 접근했다가 실패해 Floyd-Warshall 기법으로 푼 문제입니다.
문제 설명
5개의 대학교에 \(N\)개의 버스 정류장이 있으며, 각 대학교는 자체적으로 \(X\)개의 버스 노선을 운영합니다.
서로 다른 대학교에서 운영하는 동일한 번호의 버스 노선은 서로 다른 노선이므로, 총 \(5X\)개의 고유한 버스 노선이 존재합니다.
문제 풀이
초기에는 BFS를 사용하여 \(N \times N\) 크기의 버스 노선 정보를 기반으로 탐색하는 방식을 시도했습니다.
그러나 \(N\)의 최대 크기가 \(100,000\)으로 매우 크기 때문에, 이 방식은 비효율적이며 시간 초과가 발생합니다.
반면, \(X\)의 최대 크기는 \(100\)으로 상대적으로 작아, \(X\)를 기준으로 최적화하는 방법이 더 효율적임을 알 수 있습니다.
이를 해결하기 위해, 각 대학교의 버스 노선을 고유하게 변환하여 처리하였습니다.
\(new\_route\_number = route\_number + route\_index * X - 1\) 연산을 사용하여 각 대학교의 노선을 고유한 번호로 매핑했습니다.
1. 인접 행렬 초기화
\(5X \times 5X\) 크기의 2D bus
행렬을 생성하여,
정류장 \(i\)에서 정류장 \(j\)로 이동할 때 필요한 최소 환승 횟수를 저장합니다.
각 버스 노선에서 직접 연결된 정류장은 환승 없이 이동 가능하므로 bus[i][j] = 1
로 설정합니다.
2. Floyd-Warshall 알고리즘 적용
이제 Floyd-Warshall 알고리즘을 사용하여 모든 정류장 간 최소 환승 횟수를 계산합니다.
점화식은 다음과 같습니다:
\(bus[i][j] = min(bus[i][j], bus[i][k] + bus[k][j])\)
여기서,
bus[i][j]
: 정류장 \(i\)에서 정류장 \(j\)까지의 최소 환승 횟수bus[i][k] + bus[k][j]
: 정류장 \(i\)에서 \(k\)를 거쳐 \(j\)로 가는 경우
이 과정을 \(5X\)번 반복하여 모든 정류장 쌍 간의 최소 환승 횟수를 계산합니다.
3. 쿼리 처리
Floyd-Warshall 알고리즘이 끝난 후, 질문 수 \(Q\)를 입력받고, 각 질문마다 출발 정류장 \(U_i\)와 도착 정류장 \(V_i\)를 받습니다.
이미 구해둔 bus
행렬을 활용하여 \(U_i\)에서 \(V_i\)까지 가는 최소 환승 횟수를 찾고 출력합니다.
시간 복잡도 분석
Floyd-Warshall 알고리즘의 시간 복잡도는 \(O(V^3)\)이며,
여기서 \(V = 5X\)이므로 전체 시간 복잡도는: \(O(5X^3) = O(X^3)\)
따라서, \(N\)이 커도 \(X\)가 작기 때문에 충분히 효율적인 방식입니다.
코드
import sys
input = sys.stdin.readline
N, X = map(int, input().split())
routes = [[r + j * X - 1 for j, r in enumerate(map(int, input().split()))] for _ in range(N)]
sz, INF = 5*X, float('inf')
bus = [[0 if i == j else INF for j in range(sz)] for i in range(sz)]
for r in routes:
for i in r:
for j in r:
if i != j:
bus[i][j] = 1
# Floyd-Warshall Algorithm
for k in range(sz):
for i in range(sz):
if bus[i][k] < INF:
for j in range(sz):
bus[i][j] = min(bus[i][j], bus[i][k] + bus[k][j])
Q = int(input())
for _ in range(Q):
u, v = map(lambda y: y - 1, map(int, input().split()))
res = min((bus[i][j] for i in routes[u] for j in routes[v]), default=INF)
sys.stdout.write(f'{res + 1 if res < INF else -1}\n')