最大流

EK:
#include<bits/stdc++.h>
#define mst(a,b) memset(a,b,sizeof(a))
#define For(i, k, j) for(register int i = (k); i <= (j); i++)
#define INF 2147483647
using namespace std;
inline int read()
{
    int num = 0;
    char c=' ';
    bool flag = 1;
    for(;c>'9'||c<'0';c=getchar()) if(c=='-') flag = -1;
    for(;c>='0'&&c<='9';num=(num<<1)+(num<<3)+c-48,c=getchar());
    return num * flag;
}
#define N 201
#define M 100001
int g[N][N]; //残量网络 
//int f[N][N]; //实流网络 
int pre[N]; // 记录每个点的前驱
bool vis[N]; // 记录每个点是否被访问过 
int n, m;
bool bfs(int s, int t) {
	mst(pre, -1); mst(vis, 0);
	queue < int > q;
	vis[s] = 1;
	q.push(s);
	while(!q.empty()) {//无脑宽搜 
		int now = q.front();
		q.pop();
		For(i, 1, n) {//找增广路 
			if(!vis[i] && g[now][i] > 0) { //now点有边连到i且i未被访问过 
				vis[i] = 1;
				pre[i] = now;//记录前驱 
				if(i == t) {
					return 1;
				}
				q.push(i);
			}
		}
	}
	return 0;
}
inline int EK(int s, int t) {
	int v, u, d, maxflow = 0;
	while(bfs(s, t)) { //可以增广 
		v = t, d = INF;//找可增量d 
		while(v != s) {
			u = pre[v]; // u记录v的前驱 
			d = min(d, g[u][v]); 
			v = u;
		}
		maxflow += d;
		v = t;
		while(v != s) {
			u = pre[v];
			g[u][v] -= d; //残量网络中的正向边减流 
			g[v][u] += d; //残量网络中的反向边加流
//			if(f[v][u] > 0) {//实流网络中是反向边 
//				f[v][u] -= d;//减流 
//			} else {
//				f[u][v] += d;//否则加流 
//			}
			v = u;
		}
	}
	return maxflow;
}
int main()
{
	n = read(), m = read();
	int s = 1, t = n;
	For(i, 1, m) {
		int u = read(), v = read(), w = read();
		g[u][v] += w;
	}
	printf("%d\n", EK(s, t));
    return 0;
}

ISAP:

#include<bits/stdc++.h>
#define mst(a,b) memset(a,b,sizeof(a))
#define For(i, k, j) for(register int i = (k); i <= (j); i++)
#define INF 2147483647
using namespace std;
inline int read()
{
    int num = 0;
    char c=' ';
    bool flag = 1;
    for(;c>'9'||c<'0';c=getchar()) if(c=='-') flag = -1;
    for(;c>='0'&&c<='9';num=(num<<1)+(num<<3)+c-48,c=getchar());
    return num * flag;
}
#define N 50001
#define M 500001
int fir[N]; //邻接表头
int h[N]; // 当前节点的高度 
int g[N]; //g[i]:高度为i的结点个数、 
int pre[N]; //前驱 
int tot = 0; 
struct Edge { //混合网络 的边结构体 
	int to, nxt;
	int cap; //容量
	int flow; //当前流量 
}e[M]; 
inline void addedge(int u, int v, int c) {
	e[tot].to = v;
	e[tot].cap = c;
	e[tot].flow = 0;
	e[tot].nxt = fir[u];
	fir[u] = tot++;
} 
void set_h(int t, int n) {
	queue <int> q;
	mst(h, -1); mst(g, 0);
	h[t] = 0;
	q.push(t);
	while(!q.empty()) {//打宽搜打的满脸无奈 
		int v = q.front();
		q.pop();
		++g[h[v]];
		for(int i = fir[v]; ~i; i = e[i].nxt) {
			int u = e[i].to;
			if(h[u] == -1) {
				h[u] = h[v] + 1;
				q.push(u);
			}
		}
	}
//	cout << "seth over" << endl;
}
int n, m; 
int ISAP(int s, int t, int n) { //s:源点 t:汇点 n:边数 
	set_h(t, n);
	int ans = 0, u = s;
	int d;
	while(h[s] < n) {
		int i = fir[u];
		if(u == s) {
			d = INF;
		} 
		for(; ~i; i = e[i].nxt) {//搜当前点的邻接边 
			int v = e[i].to;
			if(e[i].cap > e[i].flow && h[u] == h[v] + 1) {//沿着有可增量和高度减一的方向搜 
				u = v;
				pre[v] = i;
				d = min(d, e[i].cap - e[i].flow);//找可增量d 
				if(u == t) {//到达汇点 
					while(u != s) { //往源点搜 
						int j = pre[u];
						e[j].flow += d;//正向边流量加 
						e[j^1].flow -= d;//反向边流量减
						u = e[j^1].to;
					}
					ans += d;
					d = INF;
				}
				break;//找到一条可行边,退出当前搜索,向前走 
			}
		}
		if(i == -1) {//搜完了当前节点的所有边还停在原地 
			if(--g[h[u]] == 0) { //ISAP的优化 
				break;
			}
			int hmin = n - 1;
			for(int j = fir[u]; ~j; j = e[j].nxt) {//搜u的邻接边 
				if(e[j].cap > e[j].flow) {
					hmin = min(hmin, h[e[j].to]); //取最小值 
				}
			}
			h[u] = hmin + 1; //重新标高 
			++g[h[u]];
			if(u != s) {
				u = e[pre[u] ^ 1].to;
			}
		} 
	}
	return ans;
} 
int main()
{
	n = read(), m = read();
	int s = read(), t = read();
	mst(fir, -1);
	For(i, 1, m) {
		int u = read(), v = read(), w = read();
		addedge(u, v, w); //添加正向边,即当前边的残余流量 
		addedge(v, u, 0); //添加反向边,即实流网络中当前流量 
	}
	printf("%d\n", ISAP(s, t, n));
	


    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值