https://www.acmicpc.net/problem/6086

 

6086번: 최대 유량

문제 농사꾼 존은 소들이 충분한 물을 마시길 원했다. 그래서 농장에서 우물에서 외양간을 잇는 N개의 배수관의 지도를 만들기로 했다. 존은 아주 다양한 크기의 배수관들이 완전히 우연한 방법으로 연결돼있음을 알았다. 존은 파이프를 통과하는 유량을 계산하고 싶다. 두개의 배수관이 한줄로 연결 돼 있을 때 두 관의 유량 중 최솟값으로 흐르게 된다. 예를 들어 용량이 5인 파이프가 용량이 3인 파이프와 연결되면 한개의 용량 3짜리 파이프가 된다. +---5---+

www.acmicpc.net

 


문제해설

"에드몬드 카프 알고리즘(Edmonds-Karp algorithm)" 을 활용한 "네트워크 플로우" 문제입니다.

문제 제목부터가 "최대 유량"이기 때문에, 유량관련 알고리즘을 사용해야 합니다.

에드몬드 카프 알고리즘을 모르시는분은 밑의 동영상을 참고하시면 좋을 것 같습니다.

 

https://youtu.be/Wn51_ypG_T8

위, 유튜브에서 올라온 코드 그대로 작성하면 AC를 맞을 수 있습니다.

단, 조심해야 할 것은

입력 부분에서 

		map[A].push_back(B);
		map[B].push_back(A);
		c[A][B] += w;
		c[B][A] += w;

위와 같이, 양방향에 대해서 처리를 해줘야 됩니다.

주석을 통해서 자세한 풀이를 확인해주세요.


전체코드

#include <iostream>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <limits.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define endl '\n'
//--------------------------------------------------------------------------------------
#define MAX_N 52

int c[MAX_N][MAX_N]; // 흐르는 양
int f[MAX_N][MAX_N]; // 흐르고 있는 양
int visit[MAX_N]; // 한번 que가 돌때마다 visit 이 -1로 초기화 된다.
vector<int> map[MAX_N];

// 애드몬드 카프 알고리즘
int maxFlow(int start, int end) {
	int ret = 0;
	while (1) {
		memset(visit, -1, sizeof(visit)); // 모든 정점 방문 초기화
		queue<int> q;
		q.push(start); // start 점에서 end 점까지 흘려 보낸다.
		while (!q.empty()) { 
			int front = q.front(); q.pop();
			for (int i = 0; i < map[front].size(); i++) {
				int e = map[front][i];
				if (c[front][e] - f[front][e] > 0 && visit[e] == -1) {
					// 흐를 수 있다 && 이번 BFS에서 흐른적이 없다.
					q.push(e); 
					visit[e] = front; // front에서 e로 흘렀다는 것을 알려준다.
					if (e == end) break; // end 점을 찾게되면 flow 중지
				}
			}
		}
		// 모든 경로를 찾은 경우
		if (visit[end] == -1) break; // BFS에서 end 점을 방문하지 않았다 -> 더이상 흐르는 경우가 없다.
		int flow = INT_MAX; // 최솟값을 찾기 위함
		for (int i = end; i != start; i = visit[i]) {
			flow = min(flow, c[visit[i]][i] - f[visit[i]][i]);
		}

		for (int i = end; i != start; i = visit[i]) {
			// 음의 간선이 있다고 생각함으로써 모든 경우의 수를 탐색 할 수 있게 된다.
			f[visit[i]][i] += flow;
			f[i][visit[i]] -= flow;
		}
		ret += flow;
	}
	return ret;
}

int getID(char c) {
	int ret;
	if (c >= 97) {
		ret = c - 97;
		ret += 26;
	}
	else {
		ret = c - 65;
	}
	return ret;
}

int main() {
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int N; cin >> N;
	for (int i = 0; i < N; i++) {
		char a, b; int w; cin >> a >> b >> w;
		int A = getID(a);
		int B = getID(b);
		//cout << a << " : " << A << " " << b << " : "<< B << endl;
		map[A].push_back(B);
		map[B].push_back(A);
		c[A][B] += w;
		c[B][A] += w;
	}
	cout << maxFlow(0, 25) << "\n";
}

기타

'알고리즘 > [C++]BOJ' 카테고리의 다른 글

[백준BOJ] 1671 상어의 저녁식사  (0) 2019.10.14
[백준BOJ] 11376 열혈강호2  (0) 2019.10.13
[백준BOJ] 11375 열혈강호  (0) 2019.10.13

+ Recent posts