POJ1273 网络流-->最大流-->模板级别-->最大流常用算法总结
一般预流推进算法:
算法思想:
对容量网络G 的一个预流f,如果存在活跃顶点,则说明该预流不是可行流。
预流推进算法就是要选择活跃顶点,并通过它把一定的流量推进到它的邻接顶点,尽可能将正的赢余减少为0。
由于算法最终目的是尽可能将流量推进到汇点Vt,因此算法总是首先寻求将流量推进到距离汇点Vt 最近的邻接顶点中。
由于每个顶点的距离标号可以表示顶点到汇点Vt 的距离,因此算法总是将流量沿着允许弧推进。
如果从当前活跃顶点出发没有允许弧,则增加该顶点的距离标号,使得从当前活跃顶点出发至少有一条允许弧。
算法实现基本框架:
(1) (预处理)取零流作为初始可行流,即f = { 0 },对源点Vs 发出的每条<Vs, u>,令f(Vs, u)= c(Vs, u);对任意的顶点v∈V,计算精确的距离标号d(v);令d(Vs) = n;
(2) 如果残留网络G'(V', E')中不存在活跃顶点,则算法结束,已经求得最大流,否则进入第(3)步;
(3) 在残留网络中选取活跃顶点u;如果存在顶点u 的某条出弧<u, v>为允许弧,则将min{ e(u),c'(u, v) }流量的流从顶点u 推进到顶点v;
否则令d(u) = min{ d(v)+1 | <u, v>∈E',且c'(u, v)>0}。转第(2)步。c'(u, v)为残留网络中弧<u, v>的容量。
名词解释:
赢余(excess):设u 是容量网络G(V, E)中的顶点,定义顶点u 的赢余为流入顶点u 的流量之和减去从顶点u 流出的流量之和,记为e(u)。
活跃顶点(active vertex):容量网络G 中,e(u) > 0 的顶点u(u≠Vs、Vt)称为活跃顶点。
预流(preflow):设f = { f(u, v) }是容量网络G(V, E)上的一个网络流,如果G 的每一条弧<u, v>都满足:0 ≤ f(u, v) ≤ c(u, v),<u, v>∈E。
另外,除源点Vs、汇点Vt 外每个顶点u的赢余e(u)都满足:e(u) ≥ 0,u≠Vs、Vt,则称该网络流f 为G 的预流。
算法实现:
- #include <bits/stdc++.h>//poj不支持超级头文件
- using namespace std;
- #define INF 0x3f3f3f3f
- const int maxn = 222;
- struct Push_Relablel//封装一般预流推进算法的结构体,时间复杂度O(n*n*m);
- {
- int res[maxn][maxn];//残留网络
- int dist[maxn];//距离函数
- int e[maxn];//赢余
- int n;//结点数
- int max_flow;//最大流
- void init(int x)
- {
- n = x;
- memset(res, 0, sizeof(res));
- memset(dist, 0, sizeof(dist));
- memset(e, 0, sizeof(e));
- }
- void add(int u, int v, int c)
- {
- res[u][v] += c;
- }
- int push_relablel(int s, int t)
- {
- max_flow = 0;
- queue<int> Q;
- Q.push(s);
- e[s] = INF; e[t] = INF;
- dist[s] = n;
- while(!Q.empty())
- {
- int u = Q.front(); Q.pop();
- for(int i = 1; i <= n; ++i)
- {
- int p = res[u][i] < e[u] ? res[u][i] : e[u];
- if(p>0 && (u == s || dist[u] == dist[i] + 1))
- {
- res[u][i] -=p;
- res[i][u] +=p;
- if(i == t) max_flow += p;
- e[u] -= p;
- e[i] += p;
- if(i!=s && i!=t) Q.push(i);
- }
- }
- if(u!=s && u!=t && e[u] > 0)
- {
- dist[u]++;
- Q.push(u);
- }
- }
- return max_flow;
- }
- } G;
- int main()
- {
- int m, n, u, v, c;
- while(~scanf("%d%d", &m, &n))
- {
- G.init(n);
- while(m--)
- {
- scanf("%d%d%d", &u, &v, &c);
- G.add(u, v, c);
- }
- cout<<G.push_relablel(1, n)<<endl;
- }
- return 0;
- }
最高标号预流推进算法:
算法思想:
一般预流推进算法的缺陷在于非饱和推进。
从具有最大距离标号的活跃节点开始预流推进,使得距离标号较小的活跃顶点累积尽可能多的来自距离标号较大的活跃顶点的流量,然后对累积的盈余进行推进,可能会减少非饱和推进的次数。
用优先队列优化即可。
算法实现:
- #include <bits/stdc++.h>
- using namespace std;
- #define INF 0x3f3f3f3f
- const int maxn = 222;
- struct List
- {
- int x, dist;
- List(int x_, int dist_): x(x_), dist(dist_){}
- bool friend operator < (const List& a, const List& b){
- return a.dist < b.dist;
- }
- };
- struct Push_Relablel //最高标号预流推进算法,时间复杂度O(n * n * sqrt(m))
- {
- int res[maxn][maxn];
- int dist[maxn];
- int e[maxn];
- int n;
- int max_flow;
- void init(int x)
- {
- n = x;
- memset(res, 0, sizeof(res));
- memset(dist, 0, sizeof(dist));
- memset(e, 0, sizeof(e));
- }
- void add(int u, int v, int c)
- {
- res[u][v] += c;
- }
- int push_relablel(int s, int t)
- {
- max_flow = 0;
- dist[s] = n;
- e[s] = INF; e[t] = INF;
- priority_queue<List> Q;
- Q.push(List(s, dist[s]));
- while(!Q.empty())
- {
- List q = Q.top(); Q.pop();
- int u = q.x;
- for(int i = 1; i <= n; ++i)
- {
- int p = res[u][i] < e[u] ? res[u][i] : e[u];
- if(p>0 && (u==s || dist[u] == dist[i] + 1))
- {
- res[u][i] -= p; res[i][u] += p;
- if(i == t) max_flow += p;
- e[u] -= p; e[i] += p;
- if(i != s && i != t) Q.push(List(i, dist[i]));
- }
- }
- if(u!=s && u!=t && e[u]>0)
- {
- dist[u]++;
- Q.push(List(u, dist[u]));
- }
- }
- return max_flow;
- }
- } G;
- int main()
- {
- int m, n, u, v, c;
- while(~scanf("%d%d", &m, &n))
- {
- G.init(n);
- while(m--)
- {
- scanf("%d%d%d", &u, &v, &c);
- G.add(u, v, c);
- }
- cout<<G.push_relablel(1, n)<<endl;
- }
- return 0;
- }
最短增广路算法(SAP):
算法思想:
每次在层次网络中找一个含弧最少的增广路进行增广;
算法实现步骤:
(1) 初始化容量网络和网络流;
(2) 构造残留网络和层次网络,若汇点不在层次网络中,则算法结束;
(3) 在层次网络中不断用BFS 增广,直到层次网络中没有增广路为止;每次增广完毕,在层次网络中要去掉因改进流量而导致饱和的弧;
(4) 转步骤(2)。
算法实现:
- #include <cstdio>
- #include <cstring>
- #include <queue>
- #include <iostream>
- using namespace std;
- #define INF 0x3f3f3f3f
- const int maxn = 222;
- struct EK //Edmonds-Krap 算法,又称SAP算法,时间复杂度O(n*m*m);
- {
- int res[maxn][maxn];
- int pre[maxn];
- int n;
- void init(int x)
- {
- n = x;
- memset(res, 0, sizeof(res));
- }
- void add(int u, int v, int c)
- {
- res[u][v] += c;
- }
- bool bfs(int s, int t)
- {
- queue<int> Q;
- memset(pre, -1, sizeof(pre));
- Q.push(s);
- while(!Q.empty())
- {
- int u = Q.front(); Q.pop();
- for(int i = 1; i <= n; ++i)
- {
- if(res[u][i] && pre[i] == -1) //有增广量而没有加入增广路
- {
- pre[i] = u;
- if(i == t) return true;
- Q.push(i);
- }
- }
- }
- return false;
- }
- int sap(int s, int t)
- {
- int max_flow = 0;
- while(bfs(s, t))
- {
- int a = INF;
- for(int i = t; i != s; i = pre[i])
- a = min(a, res[pre[i]][i]);
- for(int i = t; i != s; i = pre[i])
- {
- res[pre[i]][i] -= a;
- res[i][pre[i]] += a;
- }
- max_flow += a;
- }
- return max_flow;
- }
- } G;
- int main()
- {
- int n, m, u, v, c;
- while(~scanf("%d%d", &m, &n))
- {
- G.init(n);
- while(m--)
- {
- scanf("%d%d%d", &u, &v, &c);
- G.add(u, v, c);
- }
- cout<< G.sap(1, n) <<endl;
- }
- return 0;
- }
连续最短增广路算法(Dinic):
算法思想:
Dinic 算法的思想也是分阶段地在层次网络中增广。它与最短增广路算法不同之处是:在Dinic 算法中,只需一次DFS 过程就可以实现多次增广。
算法实现步骤:
(1) 初始化容量网络和网络流;
(2) 构造残留网络和层次网络,若汇点不在层次网络中,则算法结束;
(3) 在层次网络中用一次DFS 过程进行增广,DFS 执行完毕,该阶段的增广也执行完毕;
(4) 转步骤(2)。
算法实现:
- #include <bits/stdc++.h>
- using namespace std;
- #define INF 0x3f3f3f3f
- const int maxn = 222;
- struct Dinic //时间复杂度O(n*n*m)
- {
- int res[maxn][maxn];
- int dist[maxn];
- int n;
- void init(int x)
- {
- n = x;
- memset(res, 0, sizeof(res));
- }
- void add(int u, int v, int c)
- {
- res[u][v] += c;
- }
- int bfs(int s)
- {
- memset(dist, 0xff, sizeof(dist));
- dist[s] = 0;
- queue<int> Q;
- Q.push(s);
- while(!Q.empty())
- {
- int u = Q.front(); Q.pop();
- for(int i = 1; i <= n; ++i)
- {
- if(dist[i] < 0 && res[u][i] > 0)
- {
- dist[i] = dist[u] + 1;
- Q.push(i);
- }
- }
- }
- if(dist[n] > 0) return true;
- return false;
- }
- int Find(int x, int low)
- {
- int a = 0;
- if(x == n) return low;
- for(int i = 1; i <= n; ++i)
- {
- if(res[x][i] > 0 && dist[i] == dist[x] + 1 && (a = Find(i, min(low, res[x][i]))))
- {
- res[x][i] -= a;
- res[i][x] += a;
- return a;
- }
- }
- return 0;
- }
- int dinic(int s, int t)
- {
- int max_flow = 0, tmp;
- while(bfs(1))
- {
- while(tmp = Find(1, INF))
- max_flow += tmp;
- }
- return max_flow;
- }
- } G;
- int main()
- {
- int m, n, u, v, c;
- while(~scanf("%d%d", &m, &n))
- {
- G.init(n);
- while(m--)
- {
- scanf("%d%d%d", &u, &v, &c);
- G.add(u, v, c);
- }
- cout<< G.dinic(1, n) <<endl;
- }
- return 0;
- }
POJ1273 网络流-->最大流-->模板级别-->最大流常用算法总结的更多相关文章
- [转载 ]POJ 1273 最大流模板
转载 百度文库花了5分下的 不过确实是自己需要的东西经典的最大流题POJ1273 ——其他练习题 POJ3436 . 题意描述: 现在有m个池塘(从1到m开始编号,1为源点,m为汇点),及n条水渠,给 ...
- HDU2686 费用流 模板
Matrix Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
- 【Luogu】P3376网络最大流模板(Dinic)
最大流模板成为另一个被攻克的模板题. 今天QDC给我讲了一下Dinic,感觉很好懂.于是为了巩固就把这道题A掉了. 核心思想就是不断BFS分层,然后不断DFS找增广路.找不到之后就可以把答案累加输出了 ...
- hdu1533 费用流模板
Going Home Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- 最大流 && 最小费用最大流模板
模板从 这里 搬运,链接博客还有很多网络流题集题解参考. 最大流模板 ( 可处理重边 ) ; const int INF = 0x3f3f3f3f; struct Edge { int from ...
- 图论算法-最小费用最大流模板【EK;Dinic】
图论算法-最小费用最大流模板[EK;Dinic] EK模板 const int inf=1000000000; int n,m,s,t; struct node{int v,w,c;}; vector ...
- ZOJ_2314_Reactor Cooling_有上下界可行流模板
ZOJ_2314_Reactor Cooling_有上下界可行流模板 The terrorist group leaded by a well known international terroris ...
- Drainage Ditches---hdu1532(最大流, 模板)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1532 最大流模板题: EK:(复杂度为n*m*m); #include<stdio.h> ...
- HDU3376 最小费用最大流 模板2
Matrix Again Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 102400/102400 K (Java/Others)To ...
随机推荐
- 如何内网搭建NuGet服务器
NuGet 是.NET程序员熟知的给.NET项目自动配置安装library的工具,它可以直接安装开源社区中的各个公用组件,可以说是非常方便.不过,有些时候,公司内部的公用的基础类库,各个项目都有引用, ...
- sessionStorage,UserDataStorage,cookie全兼容写法存在的问题
最近央视播出了中国诗词大赛,看到了一首诗,送给大家 <春宵·春宵一刻值千金> 作者:苏轼 [宋代] 春宵一刻值千金,花有清香月有阴. 歌管楼台声细细,秋千院落夜沉沉. 好了,言归正传,今天 ...
- 数据结构中,几种树的结构表示方法(C语言实现)
//***************************************** //树的多种结构定义 //***************************************** # ...
- lua中的require机制
lua中的require机制 为了方便代码管理,通常会把lua代码分成不同的模块,然后在通过require函数把它们加载进来.现在看看lua的require的处理流程.1.require机制相关的数据 ...
- IdentityServer4 退出登录后,跳转到原来页面
IdentityServer4 退出登录后,默认会跳转到Config.Client配置的PostLogoutRedirectUris地址,那我们如何动态的跳转到原来的地址呢?实现很简单,Logout修 ...
- sublime text全程指南【转载】
前言(Prologue) Sublime Text是一款跨平台代码编辑器(Code Editor),从最初的Sublime Text 1.0,到现在的Sublime Text 3.0,Sublime ...
- 【Kafka源码】KafkaController启动过程
[TOC] 之前聊过了很多Kafka启动过程中的一些加载内容,也知道了broker可以分为很多的partition,每个partition内部也可以分为leader和follower,主从之间有数据的 ...
- winform音频播放器(有声小说[凡人修仙传])
该程序采用多线程的技术及DataGridView单元格扩展的技术 1.获取下载列表 private void GetDownList() { //System.Web.HttpUtility.UrlD ...
- SSL证书简介
前言 之前写了一篇本站点如何部署SSL证书的文章<Centos7.4下用Docker-Compose部署WordPress(续)-服务器端用Nginx作为反向代理并添加SSL证书(阿里云免费DV ...
- details和summary可以对内容进行折叠
使用<details>和<summary>元素 它可以在body的任意地方使用下面有一个小例子 <!DOCTYPE html> <html lang=&quo ...