(FF && EK && Dinic) 网络流模板

附上学习路径

https://www.luogu.org/blog/ONE-PIECE/wang-lao-liu-jiang-xie-zhi-dinic

https://www.cnblogs.com/y-clever/p/6308820.html

洛谷真是个神奇的地方:(太强了)

https://www.luogu.org/problemnew/solution/P4722

yh大佬的板子:

https://blog.csdn.net/henuyh/article/details/80637636

FF模板

const int inf = 0x7fffffff;
const int maxn = 205;
struct node
{
	int v, w, nex;
}edge[maxn * maxn];
int cnt, s, t;

int m, n; 
int head[maxn], pre[maxn], rec[maxn], flow[maxn];
stack<int> stk;
void init()
{
	cnt = 0;
	memset(head, -1, sizeof head);
}
void addedge(int u, int v, int w){
	//正向建边 
	edge[cnt] = {v, w, head[u]};
	head[u] = cnt++;
	//反向建边 
	edge[cnt] = {u, 0, head[v]};
	head[v] = cnt++;
}
int dfs(int S, int T)
{
	memset(pre, -1, sizeof pre);
	while(!stk.empty()) stk.pop();
	pre[S] = S; flow[S] = inf;
	stk.push(S);
	while(!stk.empty())	//用栈迭代替代dfs深搜 
	{
		int top = stk.top();
		stk.pop();
		int k = head[top];
		while(k != -1)
		{
			if(pre[edge[k].v] == -1 && edge[k].w > 0)
			{
				
				flow[edge[k].v] = min(flow[top], edge[k].w);
				pre[edge[k].v] = top;	//连v的点 
				rec[edge[k].v] = k;		//连v的这条边 
				stk.push(edge[k].v);
			}
			k = edge[k].nex;
		}
		if(pre[T] != -1) return flow[T];
	}
	return -1;
}
int FF(int s, int t)
{
	int ans = 0, add;
	while((add = dfs(s, t)) != -1)	//直到找不到增广路 
	{
		ans += add;
		int k = t;
		while(k != s)
		{
			edge[rec[k]].w -= add;
			edge[rec[k]^1].w += add;
			k = pre[k];
		}
	}
	return ans;
}

EK 模板

// 链式向前星
int cnt; 
struct ac{
	int v, c, nex;
}edge[maxm];
bool vis[maxn];
int head[maxn], path[maxn];
void init(){
	cnt = 0;
	memset(head, -1, sizeof(head));
} 
void addedge(int u, int v, int c){
	//正向建边 
	edge[cnt] = {v, c, head[u]};
	head[u] = cnt++;
	//反向建边 
	edge[cnt] = {u, 0, head[v]};
	head[v] = cnt++;
}
bool bfs(int s, int t){ // 找最短的增广路 
	memset(vis, 0, sizeof(vis));
	memset(path, -1, sizeof(path));
	queue<int> que;
	que.push(s);
	vis[s] = 1; 
	while (!que.empty()) {
		int u = que.front();
		que.pop();
		// 遍历u 的所有的出边 
		for (int i = head[u]; i != -1; i = edge[i].nex) {
			int v = edge[i].v;
			int c = edge[i].c;
			// 判断能否增广 
			if(vis[v] || c == 0) continue;
			path[v] = i;
			vis[v] = 1;
			que.push(v);
			if(v == t) return true;	//分层成功,找到增广路 
		}
	}
	return false;
}
int EK (int s, int t) {
	int ans = 0;
	while( bfs(s, t) ) { // 找到增广路 
		int flow = inf;
		for (int i = path[t]; i != -1; i = path[edge[i^1].v]) {
			flow = min(flow, edge[i].c);
		} 
		for (int i = path[t]; i != -1; i = path[edge[i^1].v]) {
			edge[i].c -= flow;
			edge[i^1].c += flow;
		} 
		ans += flow;
	}
	return ans;
}
// 临接矩阵
// pre记录前驱节点
int G[maxn][maxn], pre[maxn], vis[maxn], n, m;
// BFS找增广路
bool bfs(int s, int e) {
	memset(vis, 0, sizeof(vis));
	memset(pre, -1, sizeof(pre));
	pre[s] = s;
	vis[s] = 1;
	queue<int> que;
	que.push(s);
	while (!que.empty()) {
		int u = que.front();
		que.pop();
		// 访问u所有的出边, 判断能否增广
		for (int i = 0; i <= e; i++) {
			if (G[u][i] && !vis[i]) {
				pre[i] = u;
				que.push(i);
				vis[i] = 1;
				if (i == e)	return 1; // 到汇点存在增广路
			}
		}
	}
	return 0;
}
int EK(int s, int e) {
	int ans = 0;
	while (bfs(s, e)) { // 判断是否存在增广路
		int MIN = inf;
		// 遍历增广路上所有边取流量最小的边
		for (int i = e; i != s; i = pre[i]) {
			MIN = min(MIN, G[pre[i]][i]);
		}
		// 更新增广路上的流量, 正向减,反向加
		for (int i = e; i != s; i = pre[i]) {
			G[pre[i]][i] -= MIN;
			G[i][pre[i]] += MIN;
		}
		ans += MIN;
	}
	return ans;
}

Dinic

const int maxn = 1010;
const int maxm = 4e5 + 10;
const int inf = 0x3f3f3f3f;
int s, t;
struct ac{
	int v, c, nex;
}edge[maxm];
int head[maxn], dis[maxn], curedge[maxn], cnt;
void init () {
	cnt = 0;
	memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int c){
	//正向建边 
	edge[cnt] = {v, c, head[u]};
	head[u] = cnt++;
	//反向建边 
	edge[cnt] = {u, 0, head[v]};
	head[v] = cnt++;
}
bool bfs(){  //对图分层 
	memset(dis, 0, sizeof(dis));
	queue<int> que;
	que.push(s);
	dis[s] = 1;
	while(!que.empty()) {
		int u = que.front(); 
		que.pop();
		// 遍历u的所有出边 
		for (int i = head[u]; i != -1; i = edge[i].nex) {
			int v = edge[i].v;
			int c = edge[i].c;
			// 如果节点v未分过层或者 u->v流量不为0
			if( dis[v] || c == 0) continue;
			dis[v] = dis[u] + 1;	//v 为 u的下一层 压入队列 
			que.push(v);
			//if (v == e)
				//break;
		}
	}
	return dis[t] > 0; // 判断是否存在增广路,s是否能到达e 
}
int dfs(int u, int flow){
	if (u == t || flow == 0) return flow;
	//遍历u的所有的出边 
	for (int i = curedge[u]; i != -1; i = edge[i].nex) {
		int v = edge[i].v;
		int c = edge[i].c;
		// 判断 u -> v 能否增广 
		if (dis[v] != dis[u] + 1 || c == 0) continue;
		int d = dfs(v, min(flow, c));
		if (d > 0) {	//找到增广路,修改增广路上的正反向边的流量 
			edge[i].c -= d;
			edge[i ^ 1].c += d;
			curedge[u] = i;	//当前弧优化 
			return d; 
		}
	}
	dis[u] = -1; // 炸点优化 
	return 0;
}
/*
int dfs(int u, int flow){
	if (u == t) return flow;
	//遍历u的所有的出边 
	int totflow = 0;    //当前点的流量
	for (int i = curedge[u]; i != -1; i = edge[i].nex) {
		int v = edge[i].v;
		int c = edge[i].c;
		// 判断 u -> v 能否增广 
		if (dis[v] != dis[u] + 1 || c == 0) continue;
		int d = dfs(v, min(flow - totflow, c));
		if (d > 0) {	//找到增广路,修改增广路上的正反向边的流量 
			edge[i].c -= d;
			edge[i ^ 1].c += d;
			totflow += d;
			curedge[u] = i;	//当前弧优化 
			if(flow == totflow) return totflow;
		}
	}
	if(!totflow)
		dis[u] = -1; // 炸点优化 
	return totflow;
}
int Dinic(){
	int Sum = 0, d;
	while (bfs()) {// 分层 
		// copy head数组,在dfs中可以直接得到下一条没有被增广过的边
		for(int i = 0; i <= ; ++i) curedge[i] = head[i];
		//多次找增广路 
		Sum += dfs(s, inf);
	}
	return Sum;
}
*/
int Dinic(){
	int Sum = 0, d;
	while (bfs()) {// 分层 
		// copy head数组,在dfs中可以直接得到下一条没有被增广过的边
		for(int i = 0; i <= ; ++i) curedge[i] = head[i];
		//多次找增广路 
		while((d = dfs(s, inf)) > 0) {
			Sum += d;
		}
	}
	return Sum;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值