POJ 1273 - Drainage Ditches [maximum flow & EK & Dinic algorithm optimization algorithm +]

Topic Portal


Description

Every time it rains on Farmer John’s fields, a pond forms over Bessie’s favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage ditches so that Bessie’s clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into that ditch.
Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network.
Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle.


Input

The input includes several cases. For each case, the first line contains two space-separated integers, N (0 <= N <= 200) and M (2 <= M <= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections points for those ditches. Intersection 1 is the pond. Intersection point M is the stream. Each of the following N lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei <= M) designate the intersections between which this ditch flows. Water will flow through this ditch from Si to Ei. Ci (0 <= Ci <= 10,000,000) is the maximum rate at which water will flow through the ditch.


Output

For each case, output a single integer, the maximum rate at which water may emptied from the pond.


Sample Input

5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10


Sample Output

50


The meaning of problems

There are m pond (numbered from 1 to m, a source point, m is the sink) and drains the n have the given point which is connected drains of n and the maximum flow rate that can flow therethrough, seeking maximum flow from the source to the sink can flow.


answer

  • Bare maximum flow
  • Note that the title has multiple edges data

AC-Code

  • Edmonds-Karp algorithm shortest augmenting
    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    
    const int inf = 0x3f3f3f3f;
    int S, T;
    int n, m;
    
    int pre[205];
    int flow[205];
    int c[205][205];
    int BFS() {
    	memset(pre, -1, sizeof pre);
    	pre[S] = 0;
    	flow[S] = inf;
    	queue<int>que;
    	que.push(S);
    	while (!que.empty()) {
    		int op = que.front();
    		que.pop();
    		for (int i = 1; i <= n; i++) {
    			if (i == S || pre[i] != -1 || c[op][i] == 0)	continue;
    			pre[i] = op; //找到未遍历过的点
    			flow[i] = min(flow[op], c[op][i]); // 更新路径上的最小值 
    			que.push(i);
    		}
    	}
    	if (pre[T] == -1)	return -1;
    	return flow[T];
    }
    int EK(int s, int t) {
    	S = s;
    	T = t;
    	int ans = 0;
    	while (1) {
    		int k = BFS();
    		if (k == -1)	break;
    		ans += k;
    		int nw = T;
    		while (nw != S) {	//更新残量网络 
    			c[pre[nw]][nw] -= k;
    			c[nw][pre[nw]] += k;
    			nw = pre[nw];
    		}
    	}
    	return ans;
    }
    int main() {
    	while (cin >> m >> n) {
    		memset(c, 0, sizeof c);
    		for (int i = 0; i < m; i++) {
    			int x, y, z;
    			cin >> x >> y >> z;
    			c[x][y] += z;	// 这里要 += ,不然会WA;应该是有重边数据
    		}
    		cout << EK(1, n) << endl;
    	}
    }
    
  • Dinic algorithm
    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    
    const int inf = 0x3f3f3f3f;
    int n, m;
    
    struct Edge {
    	int to;
    	int next;
    	int val;
    }edge[205 << 1]; // 双向边,开 2 倍数组
    int head[205];
    int cnt; // 边的数量,从 0 开始编号
    int depth[205]; // 分层图标记深度
    
    void add(int u, int v, int w) {
    	edge[cnt].to = v;
    	edge[cnt].next = head[u];
    	edge[cnt].val = w;
    	head[u] = cnt++;
    }
    
    // bfs分层图
    bool bfs(int s, int t) { 
    	queue<int>q;
    	memset(depth, 0, sizeof depth);
    	depth[s] = 1; // 源点深度为 1
    	q.push(s);
    	while (!q.empty()) {
    		int u = q.front();
    		q.pop();
    		for (int i = head[u]; ~i; i = edge[i].next) {
    			int v = edge[i].to;
    			if (edge[i].val > 0 && depth[v] == 0) { // 如果残量不为0,且 v 还未分配深度
    				depth[v] = depth[u] + 1;
    				q.push(v);
    			}
    		}
    	}
    	return depth[t]; // 汇点深度为 0:不存在分层图,返回false;
    					 //           非 0 :存在增广路,返回true
    }
    
    // dfs寻找增广路
    int dfs(int u, int flow, int t) { 
    	if (u == t || flow <= 0) // 到达汇点
    		return flow;
    	int rest = flow;
    	for (int i = head[u]; ~i; i = edge[i].next) {
    		int v = edge[i].to;
    		if (depth[v] == depth[u] + 1 && edge[i].val != 0) { // 满足分层图、残量>0 两个条件
    			int k = dfs(v, min(rest, edge[i].val), t); // 向下增广
    			rest -= k;
    			edge[i].val -= k; // 正向边减
    			edge[i ^ 1].val += k; // 反向边加
    		}
    	}
    	return flow - rest; // flow:推送量,rest:淤积量,flow - rest:接受量/成功传递量
    }
    
    int Dinic(int s, int t) {
    	int ans = 0;
    	while (bfs(s, t)) {
    		while (int d = dfs(s, inf, t))
    			ans += d;
    	}
    	return ans;
    }
    
    int main() {
    	while (cin >> m >> n) {
    		cnt = 0;
    		memset(head, -1, sizeof head);
    		for (int i = 1; i <= m; i++) {
    			int x, y, z;
    			cin >> x >> y >> z;
    			add(x, y, z);
    			add(y, x, 0);
    		}
    		cout << Dinic(1, n) << endl;
    	}
    }
    
  • Dinic optimization algorithm + + useless current arc point optimization
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int inf = 0x3f3f3f3f;
int n, m;

struct Edge {
	int to;
	int next;
	int val;
}edge[205 << 1]; // 双向边,开 2 倍数组
int head[205];
int cnt; // 边的数量,从 0 开始编号
int depth[205]; // 分层图标记深度
int cur[205]; // 当前弧优化,记录当前点 u 循环到了哪一条边
void add(int u, int v, int w) {
	edge[cnt].to = v;
	edge[cnt].next = head[u];
	edge[cnt].val = w;
	head[u] = cnt++;
}

// bfs分层图
bool bfs(int s, int t) { 
	queue<int>q;
	memset(depth, 0, sizeof depth);
	depth[s] = 1; // 源点深度为 1
	cur[s] = head[s];
	q.push(s);
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		for (int i = head[u]; ~i; i = edge[i].next) {
			int v = edge[i].to;
			if (edge[i].val > 0 && depth[v] == 0) { // 如果残量不为0,且 v 还未分配深度
				depth[v] = depth[u] + 1;
				cur[v] = head[v]; //------当前弧优化,注意在bfs里,这样做到了“按需赋值”,因为Dinic本来上界就松得一匹, BFS的过程中不连通的点根本就不用再管了...
				if (v == t) // -----分层图汇点优化:遇到汇点直接返回------
					return true;
				q.push(v);
			}
		}
	}
	return depth[t]; // 汇点深度为 0:不存在分层图,返回false;
					 //           非 0 :存在增广路,返回true
}

// dfs寻找增广路
int dfs(int u, int flow, int t) { 
	if (u == t || flow <= 0) // 到达汇点
		return flow;
	int rest = flow;
	for (int i = cur[u]; ~i; i = edge[i].next) {
		int v = edge[i].to;
		if (depth[v] == depth[u] + 1 && edge[i].val != 0) { // 满足分层图、残量>0 两个条件
			int k = dfs(v, min(rest, edge[i].val), t); // 向下增广
			if (k < 0) // ------无用点优化-----
				depth[v] = 0;
			rest -= k;
			edge[i].val -= k; // 正向边减
			edge[i ^ 1].val += k; // 反向边加
			if (rest <= 0) //------剩余量优化:在进行增广的时候,如果该节点已经没有流量,直接退出------
				break;
		}
	}
	return flow - rest; // flow:推送量,rest:淤积量,flow - rest:接受量/成功传递量
}
int Dinic(int s, int t) {
	int ans = 0;
	while (bfs(s, t)) {
		while (int d = dfs(s, inf, t))
			ans += d;
	}
	return ans;
}
int main() {
	while (cin >> m >> n) {
		cnt = 0;
		memset(head, -1, sizeof head);
		for (int i = 1; i <= m; i++) {
			int x, y, z;
			cin >> x >> y >> z;
			add(x, y, z);
			add(y, x, 0);
		}
		cout << Dinic(1, n) << endl;
	}
}
Published 104 original articles · won praise 60 · views 5848

Guess you like

Origin blog.csdn.net/Q_1849805767/article/details/103596497