HDU3549 Flow Problem——最大流(EK、Dinic模板)

点这里

题意: 给定一个有向图,求点1到点n的最大流。
题解: 算法详见Dinic算法研究总结


EK模板

#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 300;

int T, n, m, k;
int pre[N], G[N][N];	//记录前驱节点、存图
int bfs(int s, int t){
	int flow[N];		//到节点i的流量
	memset(pre, -1, sizeof pre);	//重置前驱节点
	flow[s] = inf;	pre[s] = 0;		//源点的容量无限
	queue<int> Q; Q.push(s);
	while(!Q.empty()){
		int u = Q.front(); Q.pop();
		if(u == t)	break;
		for(int i = 1; i <= t; i++)
			if(i != s && G[u][i] > 0 && pre[i] == -1){	//保证i不是起点,i没有去过,i还有残留容量
				pre[i] = u;
				Q.push(i);
				flow[i] = min(flow[u], G[u][i]);
			}
	}
	if(pre[t] == -1)	return -1;
	return flow[t];
}
int maxflow(int s, int t){
	int Maxflow = 0;
	while(1){
		int flow = bfs(s, t);
		if(flow == -1)	break;
		int cur = t;
		while(cur != s){
			int fa = pre[cur];
			G[fa][cur] -= flow;
			G[cur][fa] += flow;	//更新残留容量
			cur = fa;
		}
		Maxflow += flow;	//这条增广路的流量汇入汇点
	}
	return Maxflow;
}
int main(){
	scanf("%d", &T);
	while(T--){
		memset(G, 0, sizeof G);
		scanf("%d%d", &n, &m);
		while(m--){
			int u, v, w;
			scanf("%d%d%d", &u, &v, &w);
			G[u][v] += w;	//可能有重边 
		}
		printf("Case %d: %d\n", ++k, maxflow(1, n));
	}
	return 0;
}

Dinic模板

#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 20;
const int M = 1005;

int T, n, m, k;
int s, t, cnt;
int cur[N];
int head[N];
int depth[N];
struct edge{	int v, w, next;} e[2 * M];
void add(int u, int v, int w){	e[cnt].v = v, e[cnt].w = w, e[cnt].next = head[u], head[u] = cnt++;}
void addedge(int u, int v, int w){	add(u, v, w); add(v, u, 0);}	//有向图,注意加的第二条边
void init(){	s = 1, t = n, cnt = 0;	for(int i = 1; i < N; i++)	head[i] = -1;}
bool bfs(){
	for(int i = 1; i <= t; i++)	depth[i] = 0;
	queue<int> Q; 
	Q.push(s);	depth[s] = 1;
	while(!Q.empty()){
		int u = Q.front(); Q.pop();
		for(int i = head[u]; ~i; i = e[i].next){
			int v = e[i].v, w = e[i].w;
			if(depth[v] == 0 && w > 0){	//点v没有去过并且还有残留容量
				depth[v] = depth[u] + 1;
				Q.push(v);
			}
		}
	}
	if(depth[t] > 0)	return 1;
	return 0;
}
int dfs(int u, int flow){
	if(u == t)	return flow;
	for(int& i = cur[u]; ~i; i = e[i].next){	//&符号,改变i的同时也会改变cur[u]
		int v = e[i].v, w = e[i].w;
		if(depth[v] == depth[u] + 1 && w != 0){	//点v没有去过并且还有残留容量
			int minflow = dfs(v, min(flow, w));
			if(minflow > 0){
				e[i].w -= minflow;
				e[i ^ 1].w += minflow;	//更新残留容量
				return minflow;
			}
		}
	}
	return 0;
}
int Dinic(){
	int ans = 0;
	while(bfs()){
		for(int i = 1; i <= t; i++)	cur[i] = head[i];
		while(int d = dfs(s, inf))	ans += d;
	}
	return ans;
}
int main(){
	scanf("%d", &T);
	while(T--){
		scanf("%d%d", &n, &m);
		init();
		while(m--){
			int u, v, w;
			scanf("%d%d%d", &u, &v, &w);
			addedge(u, v, w);
		}
		printf("Case %d: %d\n", ++k, Dinic());
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值