证明增广路算法的正确性及dinic算法的使用
来源:互联网 发布:犀牛软件调整模型尺寸 编辑:程序博客网 时间:2024/05/21 10:57
一直对增广路这种贪心思想表示怀疑,今天看到一个很好的证明。
首先介绍割的概念,所谓图的割,指的是某个顶点集合S属于V,从S出发的所有边的集合成为割(S,V\S),这些边的容量和被称为割的容量,如果有源点s属于S,汇点t属于V\S,则称之为s-t割,如果将s-t割的所有边都在原图中去掉,则不再有s->t的路径。
容易得到,对于任意一个s-t割,总有f的流量<=割的容量,根据平衡条件,当且仅当割为最小割,流为最大流时去等号
首先,对于ford-Fulkerson算法求出的流为f,f对应的残余网络中从s可达的顶点集合为S,因为f对应的残余网络中不存在从s->t的路径了,那么显然,在残余网络中,任意一条从S->
V\S 中的边流量f=c,任意一条从反向弧f=0,这个一定是满足,如果不满足,那么S集合还可以扩充顶点,与前提矛盾。因此,S->V\S的割的容量等于流的大小。则可以证明裸的増广路ford算法是正确的。
再说一下dinic算法,dinic算法总是寻找最短的増广路并沿着它增广,増广路的长度不会在增广过程中改变,则当无法增广时,说明分层图上没有可以增广的路线了,这有两种情况,第一,已经求出了最大流,第二,可能存在长一些的増广路可以继续增广,因此,继续bfs构造分层网络。每次完成后最短増广路长度+1,由于最短路<n,则最对重复n-1次bfs就可完成了。
#include <queue>#include <vector>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int max_node = 20;const int INF = 0x3f3f3f3f;struct Edge{ int to,cap,rev; Edge(int t,int c,int r):to(t),cap(c),rev(r) {}};vector<Edge> G[max_node];int node_num,edge_num;int dis[max_node]; //各顶点到源点的无权距离,通过BFS得到int cur[max_node]; //当前弧优化void push_edge(int from,int to,int cap){ //直接建立残余网络,插入反向边的方式很巧妙 G[from].push_back( Edge(to,cap,G[to].size()) ); G[to].push_back( Edge(from,0,G[from].size()-1) );}void BFS(){ memset(dis, -1, sizeof(dis)); dis[1]=0; queue<int> q; q.push(1); while(!q.empty()){ int t = q.front(); q.pop(); for(int k = 0; k < G[t].size(); k++){ Edge &e = G[t][k]; if(e.cap > 0 && dis[e.to] == -1){ // 沿着残余网络进行标记 dis[e.to] = dis[t] + 1; q.push(e.to); } } }}int DFS(int u, int v, int res){ if( u == v) return res; for(int k = cur[u]; k < G[u].size(); k++){ int to = G[u][k].to; if( G[u][k].cap > 0 && dis[to] == dis[u] + 1){ //沿着残余网络深度优先搜索 int x = DFS(to, v, min(res, G[u][k].cap)); if(x > 0){ G[u][k].cap -= x; int rev = G[u][k].rev; G[to][rev].cap += x; cur[u] = k; return x; } } } return 0;}int maxFlow(){ int flow = 0; while(1) { memset(cur, 0, sizeof(cur)); //当前弧自然从0开始 BFS(); //构造分层图 if(dis[node_num] == -1){ //最小割出现,找不到增广路 return flow; } //在当前分层图上进行最短路增广,如果无法继续增广,则说明当前分层图不存在增广路了,需要重新构造更长路径的分层图 while( int x = DFS(1, node_num, INF) ){ flow += x; } }}int main(){#ifdef LOCAL_DEBUG freopen("input.txt" ,"r", stdin);#endif // LOCAL_DEBUG int T,cas=1; scanf("%d" ,&T); while(T--){ printf("Case %d: ",cas++); for(int i=0; i<max_node; i++) G[i].clear(); node_num = edge_num = 0; scanf("%d%d" ,&node_num, &edge_num); int from, to, cap; for(int i=1; i<=edge_num; i++){ scanf("%d%d%d" ,&from ,&to, &cap); push_edge(from, to, cap); } printf("%d\n" ,maxFlow()); }}
1 0
- 证明增广路算法的正确性及dinic算法的使用
- 关于最大流增广路径算法的正确性的证明
- krusal算法正确性的证明
- 全排列算法的正确性证明
- 哈夫曼树构造算法的正确性证明
- 算法学习二:循环不变式证明算法的正确性
- Dijkstra 算法 -方法、算法、代码和正确性的证明
- 网络流DINIC增广路算法介绍
- 算法正确性证明三要素
- 贪心算法正确性证明
- 最小生成树的prim算法贪心正确性的证明
- 最小生成树的prim算法贪心正确性的证明
- 最大流dinic算法的优化模板 当前弧优化,多路增广
- 区间树中区间重叠检测算法正确性的证明
- 一道博弈的面试题及其算法正确性证明
- 部分背包问题的贪心算法正确性证明
- 有向图Kosaraju算法的正确性证明
- 网络流增广路Edmonds-Karp算法 与 Dinic算法
- 不用加减乘除做加法47
- Python装饰器单例
- Spark源码解读(6)——Shuffle过程
- Android 可拖拽的GridView效果实现, 长按可拖拽和item实时交换
- Android内容提供者Provider
- 证明增广路算法的正确性及dinic算法的使用
- jsf2入门demo
- noip2011 day2-2 聪明的质监员
- jQuery获取Select选择的Text和 Value
- 只能游客登录以及ubuntu输入密码登录后继续回到登录界面
- php与java通用AES加密解密算法
- 解决 [warn] _default_ VirtualHost overlap on port 80, the first has precedence
- HttpURLConnection+AsyncTask+接口回调实现简易get联网请求封装框架
- input文本框中value值有双引号的问题