반응형
https://www.acmicpc.net/problem/2350
25/10/29
최소 스패닝 트리의 아이디어를 사용하는 문제이다.
문제 접근 방식:
주어지는 쿼리의 개수는 $K \leq 10\ 000$이고, 정점의 수 $N \leq 1\ 000$, 간선의 수 $M \leq 100\ 000$이다.
각 쿼리마다 모든 경로의 개수를 세는건 아무래도 좀 힘들 것 같다.(경로의 개수의 상한이 어느정도인지는 몰라도...)
결국 배가 지나가는 경로를 하나 잡으면 그 경로 상의 운하 폭의 "최솟값"이 지나가는 배의 폭을 결정한다.
즉, 우리는 배의 폭을 최대화하고 싶으므로, 어떤 경로를 잡던 간에 운하 폭의 "최솟값"이 "최대화"되기를 원한다.
따라서, 그리디적으로 생각해보면 그냥 최대 스패닝 트리(최소스패닝이 아니다)를 잡으면 된다.
이후 두 정점을 잡으면 그 트리를 따라가도록 경로를 잡으면 경로는 항상 유일하고, 가장 큰 운하폭을 따라가도록 경로를 만들 수 있다.
아래는 내가 위의 접근 방식과 같이 작성한 C++ 코드이다. 더보기를 누르면 확인할 수 있다.
더보기
// 2350번 대운하
// MST
/*
접근 방법:
최대 스패닝 트리를 만들자.
이후 경로는 유일하다.
*/
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
#define fastio ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define endl '\n'
struct edge{
int u, v, w;
bool operator<(const edge& other) const {
return w < other.w;
}
};
int _find(int node, vector<int>& parent){
if (parent[node] != node){
parent[node] = _find(parent[node], parent);
}
return parent[node];
}
void _merge(int node1, int node2, vector<int>& parent, vector<int>& sz){
int p1 = _find(node1, parent), p2 = _find(node2, parent);
if (p1 == p2) return;
if (sz[p1] > sz[p2]){
parent[p2] = p1;
sz[p1] += sz[p2];
} else {
parent[p1] = p2;
sz[p2] += sz[p1];
}
return;
}
int bfs(int start, int end, const vector<vector<pair<int, int>>>& G){
int N = G.size();
vector<int> vis(N, 1001);
queue<int> Q;
Q.push(start);
vis[start] = 1000;
while (!Q.empty()){
int now = Q.front(); Q.pop();
if (now == end){
return vis[end];
}
for (auto near : G[now]){
int nxt = near.first; int w = near.second;
if (vis[nxt] == 1001){
vis[nxt] = min(vis[now], w);
Q.push(nxt);
}
}
}
return 1000;
}
int main(void){
fastio
int N, M, K; cin >> N >> M >> K;
vector<int> parent(N, 0);
for (int i = 0; i < N; ++i){
parent[i] = i;
}
vector<int> sz(N, 1);
vector<edge> E;
int i, j, w;
for (int a = 0; a < M; ++a){
cin >> i >> j >> w;
i--; j--;
E.push_back({i, j, w});
}
sort(E.begin(), E.end());
vector<vector<pair<int, int>>> G(N);
int cnt = 0;
while (!E.empty() && (cnt < N-1)){
edge e = E.back(); E.pop_back();
if (_find(e.u, parent) != _find(e.v, parent)){
_merge(e.u, e.v, parent, sz);
G[e.u].push_back({e.v, e.w});
G[e.v].push_back({e.u, e.w});
cnt++;
}
}
int u, v;
while (K--){
cin >> u >> v; u--; v--;
cout << bfs(u, v, G) << endl;
}
return 0;
}
반응형
'알고리즘 > 백준 문제 풀이' 카테고리의 다른 글
| [Python] 25214번 크림 파스타 (0) | 2026.02.24 |
|---|---|
| [C++] 21624번 Fence (0) | 2026.02.23 |
| [C++] 5051번 피타고라스의 정리 (0) | 2026.02.21 |
| [C++] 31435번 기숙사 비밀번호 구하기 (0) | 2026.02.20 |
| [C++] 7881번 YAPTCHA (0) | 2026.02.19 |