[C++]간선 끊어가기 2 - 백준14286
문제
풀이
문제 해석을 하자면,
- 이 문제는 Min-Cut 문제인데, 우리는 이를 Max-Flow로 풀 수 있다.
풀이
- Max-Flow 로 해결
코드
// Dinic's
#include<iostream>
#include<vector> // tree
#include<queue> // bfs
#include<algorithm> // fill
#define INF 987654321
using namespace std;
int c[505][505]; // 용량
int f[505][505]; // 유량
vector<int> vc[505]; // tree
int level[505]; // 레벨 그래프
int work[505];
int N, M, S, T; // 정점 수, 에지 수, 시작 노드, 끝 노드
bool bfs() {
// init
fill(level, level + 505, -1);
queue<int> qu; // bfs
level[S] = 0;
qu.push(S);
while (!qu.empty()) {
int cur = qu.front();
qu.pop();
for (int i = 0; i < vc[cur].size(); i++) {
int nxt = vc[cur][i];
if (c[cur][nxt] <= f[cur][nxt] || level[nxt] != -1) continue;
// 레벨이 아직 정해지지 않았고 잔여용량이 0이상은 계속 진행
level[nxt] = level[cur] + 1; // level 기록 (그냥 깊이 기록임)
qu.push(nxt);
}
}
return level[T] != -1; // -1 이면 false 반환(종료 의미)
}
int dfs(int cur, int flow) {
// base condition
if (cur == T) return flow; // cur -> depth로 이해
for (int i = work[cur]; i < vc[cur].size(); i++) {
int nxt = vc[cur][i];
if (level[nxt] - level[cur] != 1 || c[cur][nxt] <= f[cur][nxt]) continue;
// 레벨 차가 1이고, 잔여용량이 0이상은 계속 진행
// 최소 유량 탐색
int minF = dfs(nxt, min(c[cur][nxt] - f[cur][nxt], flow));
// 유량 update
if (minF > 0) {
f[cur][nxt] += minF;
f[nxt][cur] -= minF;
work[cur] = i; // index 기록해서 시간 단축
return minF;
}
}
work[cur] = vc[cur].size();
return 0;
}
int main() {
// speed up
ios::sync_with_stdio(0);
cin.tie(0);
// input
cin >> N >> M;
int n1, n2, w;
for (int i = 0; i < M; i++) {
cin >> n1 >> n2 >> w;
vc[n1].push_back(n2);
vc[n2].push_back(n1); // 양방향
c[n1][n2] += w; // 양방향 간선이므로, 양쪽으로 용량 할당
c[n2][n1] += w;
}
cin >> S >> T;
// run
int maximumFlow = 0; // 제거된 최소 간선 가중치 합
while (true) {
if (!bfs()) break; // 종료
fill(work, work + 505, 0);
int flow = dfs(S, INF);
// 최대 유량 update
maximumFlow += flow;
}
// output
cout << maximumFlow;
return 0;
}
느낀점
생략
댓글남기기