문제: BOJ 1185 - 유럽여행
각 나라에 도착할 때 드는 비용 \(C_i\) 와 길을 통과할 때 드는 통행료 \(L_j\) 가 있을 때,
모든 나라를 최소 한 번 이상 방문하고 시작 나라로 돌아오는 최소 비용을 구하는 문제다.
핵심은 “여행 계획”을 MST 문제로 비용 변형해서 떨어뜨리는 것이다.
문제 정보
문제 링크: https://www.acmicpc.net/problem/1185
문제 요약:
- 나라 수 \(N\), 길 수 \(P\)가 주어진다.
- i번 나라에 도착할 때 비용 \(C_i\)를 낸다.
- 길 \(j\): \(S_j \leftrightarrow E_j\) 를 통과할 때 통행료 \(L_j\)를 낸다.
- 시작 나라를 정할 수 있고, 여행이 끝났을 때 시작 나라로 돌아와야 한다.
- 모든 나라를 최소 한 번 이상 방문하면서 총 비용을 최소화한다.
제한 조건:
- 시간 제한: 2초
- 메모리 제한: 128MB
- \(5 \le N \le 10{,}000\)
- \(N-1 \le P \le 100{,}000\)
- \(1 \le C_i \le 1{,}000\)
- \(0 \le L_j \le 1{,}000\)
입출력 예제
입력 1:
| |
출력 1:
| |
접근 방식
핵심 관찰 1: 남겨야 하는 길은 결국 “스패닝 트리”로 충분
문제 서술상 지도에서 길을 최대한 제거하려면 \(N-1\)개의 길만 남겨야 하고, 그래프가 연결되어야 한다.
따라서 남는 길 집합은 스패닝 트리가 된다.
즉, 우리는 “어떤 스패닝 트리를 남길 것인가”를 고르면 된다.
핵심 관찰 2: 트리 위에서 모든 정점을 방문하고 원점으로 돌아오려면 각 간선을 최소 2번 지난다
트리에서 시작점으로 돌아오면서 모든 정점을 방문하려면, 각 간선은 서브트리로 들어갔다가 다시 나와야 하므로 최소 2번(왕복) 통과한다.
그리고 DFS 방식으로 돌면 각 간선을 정확히 2번(양 방향 1번씩) 사용하는 루트를 항상 만들 수 있다.
핵심 관찰 3: 간선 비용을 \(W(u,v)=2L(u,v)+C_u+C_v\) 로 바꾸면 총 비용이 “간선 합 + 시작 도시 비용”으로 정리된다
트리의 간선 \((u,v)\)를 양 방향으로 1번씩 건너면 비용은 다음처럼 정리된다.
- \(u \rightarrow v\): 통행료 \(L\) + 도착 비용 \(C_v\)
- \(v \rightarrow u\): 통행료 \(L\) + 도착 비용 \(C_u\)
따라서 \((u,v)\)를 왕복(양 방향 1번씩)할 때의 비용은
\[ 2L + C_u + C_v \]가 된다.
그리고 시작점에서는 “처음 도착” 비용 \(C_{start}\)가 한 번 필요하므로,
전체 최소 비용은 다음 형태로 된다.
- 정답 = \(\min_i C_i\) + (변형 가중치 \(W\)로 만든 MST의 가중치 합)
즉,
- 모든 간선을 \(W(u,v)=2L+C_u+C_v\)로 바꾼 뒤
- 그 가중치로 MST를 구하고
- 마지막에 \(\min C_i\)를 더하면 된다.
알고리즘 설계 (Mermaid Flowchart)
flowchart TD
A["입력 N, P도착 비용 C[i]도로 (u, v, L)"] --> B["minC = min(C[i]) 계산"]
B --> C["각 도로의 가중치 변형W = 2*L + C[u] + C[v]"]
C --> D["간선 W 기준 오름차순 정렬"]
D --> E["크루스칼 MSTDSU로 사이클 방지"]
E --> F["ans = minC + MST 가중치 합 출력"]
복잡도 분석
| 항목 | 복잡도 | 비고 |
|---|---|---|
| 시간 복잡도 | \(O(P \log P)\) | 간선 정렬이 지배 |
| 공간 복잡도 | \(O(N+P)\) | 간선 저장 + DSU |
코너 케이스 및 실수 포인트
| 케이스 | 설명 | 처리 방법 |
|---|---|---|
| 큰 누적합 | \(P\)가 크고 가중치 합이 커질 수 있음 | long long 사용 |
| 1-indexed 입력 | 나라 번호가 1..N | DSU/배열도 1..N로 맞춤 |
| 정렬 기준 | 변형된 가중치 \(W\)로 정렬해야 함 | 입력 L 그대로 정렬하면 오답 |
| 시작 도시 비용 | 시작점 비용은 한 번만 추가 | minC를 맨 마지막에 더함 |
구현 코드
C++
| |
![Featured image of post [Algorithm] C++ 백준 1185번: 유럽여행](/post/algorithm/2025-12-19-boj-1185-europe-travel-mst-kruskal-cpp-solution/wordcloud_hu_8e9eab6f391a4f4a.png)
![[Algorithm] C++ 백준 32231번: 재우의 삼수강](/post/algorithm/2025-12-20-boj-32231-jaewoos-third-retake-hyperbolic-geometry-cpp-solution/wordcloud_hu_6b5d9f28adedfd92.png)
![[Algorithm] C++ 백준 3752번: 최대공약수 행렬식](/post/algorithm/2025-12-20-boj-3752-gcd-matrix-determinant-cpp-solution/wordcloud_hu_1490cf2b4f293afc.png)
![[Algorithm] C++ 백준 1185번: 유럽여행](/post/algorithm/2025-12-19-boj-1185-europe-travel-mst-kruskal-cpp-solution/wordcloud_hu_a7973902548ef27b.png)
![[Algorithm] C++ 백준 13324번: BOJ 수열 2](/post/algorithm/2025-12-19-boj-13324-boj-sequence-2-cpp-solution/wordcloud_hu_5564e49074c47ebd.png)
![[Algorithm] C++ 백준 13539번: 트리와 쿼리 11](/post/algorithm/2025-12-19-boj-13539-tree-and-query-11-link-cut-tree-cpp-solution/wordcloud_hu_22549d9781144aba.png)
![[Algorithm] C++ 백준 2988번: 아보가드로](/post/algorithm/2025-12-19-boj-2988-avogadro-cpp-solution/wordcloud_hu_504f3f1bc728ef52.png)
![[Algorithm] C++ 백준 5813번: 이상적인 도시](/post/algorithm/2025-12-19-boj-5813-ideal-city-cpp-solution/wordcloud_hu_8653825e20480456.png)
![[Algorithm] C++/Python 백준 16901번: XOR MST](/post/algorithm/2025-08-14-boj-16901-xor-mst-cpp-python-solution/wordcloud_hu_5a04de18b2ccb6ef.png)
![[Algorithm] C++ 백준 17965번: Absolute Game](/post/algorithm/2025-12-19-boj-17965-absolute-game-cpp-solution/wordcloud_hu_f6800a55fcd520be.png)
![[Algorithm] C++ 백준 12963번: 달리기](/post/algorithm/2025-08-14-boj-12963-running-mincut-dsu-powers-of-three/wordcloud_hu_91bfa10af871213a.png)