【图】Dinic(n^2m)
来源:互联网 发布:java解压缩gz文件 编辑:程序博客网 时间:2024/05/01 15:51
struct Edge{int from,to,cap,flow;void AddEdge(int from,int to,int cap){edges.push_back((Edge){from,to,cap,0});edges.push_back((Edge){to,from,0,0}});m=edges.size();G[from].push_back(m-2);G[to].push_back(m-1);}};struct Dinic{int n,m,s,t;vector<Edge> edges;vector<int> G[maxn];bool vis[maxn];int d[maxn];int cur[maxn];bool BFS(){memset(vis,0,sizeof(vis));queue<int> Q;Q.push(s);d[s]=0;vis[s]=1;while(!Q.empty()){int x=Q.front(); Q.pop();for(int i=0;i<G[x].size();i++){Edge& e=edges[G[x][i]];if(!vis[e.to] && e.cap>e.flow){vis[e.to]=1;d[e.to]=d[x]+1;Q.push(e.to);}}}return vis[t];}int DFS(int x,int a){if(x==t || a==0)return a;int flow=0,f;for(int& i=cur[x];i<G[x].size();i++){Edge& e=edges[G[x][i]];if( d[x]+1==d[e.to] && (f=DFS(e.to,min(a,e.cap-e.flow)))>0 ){e.flow+=f;edges[G[x][i]^1].flow-=f;flow+=f;a-=f;if(a==0)break;}}return flow;}int Maxflow(int s,int t){this->s=s,this->t=t;int flow=0;while(BFS()){memset(cur,0,sizeof(cur));flow+=DFS(s,INF);}return flow;}};
伪代码
下面是dfs的过程:
[c-sharp] view plaincopy- ps;
- While outdegree(s)>0
- up.top;
- if u<>t
- if outdegree(u)>0
- 设(u,v)为层次图中的一条边;
- pp,v;
- else
- 从p和层次图中删除点u,
- 以及和u连接的所有边;
- else
- 增广p(删除了p中的饱和边);
- 令p.top为p中从s可到达的最后顶点;
- end while
[c-sharp] view plaincopy
- ps;
- While outdegree(s)>0
- up.top;
- if u<>t
- if outdegree(u)>0
- 设(u,v)为层次图中的一条边;
- pp,v;
- else
- 从p和层次图中删除点u,
- 以及和u连接的所有边;
- else
- 增广p(删除了p中的饱和边);
- 令p.top为p中从s可到达的最后顶点;
- end while
在程序里,p表示找到的增广路径,p.top为路径中的最后一个顶点。一开始,p中只有源点。
整个While循环分为2个操作。如果p的最后一个顶点为汇点,也就是说找到了增广路,那么对p增广,注意到增广后一定有一条或多条p中的边被删除了。这时,我们使增广路径后退至p中从源点可到达的最后一个顶点。
如果p的最后一个顶点不为汇点,那么观察最后那个的顶点u 。若在层次图中存在从u连出的一条边,比如(u,v),我们就将顶点v放入路径p中,继续dfs遍历;否则,点u对之后的dfs遍历就没有用了,我们将点u以及层次图中连到u的所有边删除,并且在p中后退一个点。
Dfs过程将会不断重复这2个操作,直到从源点连出的边全部被删除为止。
nocow
bool build()//建立层次图{int x,y;memset(d,-1,sizeof(d));memset(G,-1,sizeof(G));bg=ed=d[s]=0;Q[ed++]=s;G[s]=g[s];while(bg<ed){x=Q[bg++];for(int i=g[x];i+1;i=np[i]){y=to[i];if(cap[i]&&d[y]==-1){d[y]=d[x]+1;G[y]=g[y];if(y==t)return true;Q[ed++]=y;}}}return false;} int find(int x,int low=inf)//进行增广{if(x==t)return low;int ret=0,y;for(int &i=G[x];i+1;i=np[i])//注意i是引用{y=to[i];if(cap[i] && d[y]==d[x]+1 && (ret=find(y,low<?cap[i]))){cap[i]-=ret;cap[vp[i]]+=ret;return ret;}}return 0;} int dinic()//主过程{int flow;while(build())while(flow=find(s))cnt+=flow;return 0;}
非递归
//Author: dd_engivoid Dinic(){ for(;;){ BFS(); if(D[T]==-1)break; int path_n=0; int x=S; memcpy(cur,E,sizeof(cur)); for(;;){ if(x==T){ int mink=-1,delta=INT_MAX; for(int i=0;i<path_n;++i){ if(path[i]->c<delta){ delta=path[i]->c; mink=i; } } for(int i=0;i<path_n;++i){ path[i]->c-=delta; path[i]->back->c+=delta; } path_n=mink; x=path[path_n]->x; } edge* e; for(e=cur[x];e;e=e->next){ if(e->c==0) continue; int y=e->y; if(D[x]+1==D[y]) break; } cur[x]=e; if(e){ path[path_n++]=e; x=e->y; } else{ if(path_n==0) break; D[x]=-1; --path_n; x=path[path_n]->x; } } }}
0 0
- 【图】Dinic(n^2m)
- 1!+2!+...+m!<n
- 1!+2!+3!+。。。+m!<n
- 输出n-m-n
- 1!+2!+。。。+m!<n,求m的值
- 1!+2!+。。。+m!<n,求m的值
- (0! + 1! + 2! + 3! + 4! + ... + n!)%m
- (0! + 1! + 2! + 3! + 4! + ... + n!)%m
- 给定正整数 N, 求使N < 2^m 成立的最小m(C语言版)
- 输入m和n,从1,2,3...n中找出和为m的组合
- 求集合{1,2,...,n}的长度小于M(M<=n)的所有子集
- 求集合{1,2,...,n}的长度等于M(M<n)的所有子集
- 已知n,计算1+2+3+……+m>=n的最小m
- poj 1036 n!/(n-m)!*m!
- m选n算法
- M选N
- M*N的矩阵
- sigma(n^m)
- Google的Guava之Collection升华
- Linux 学习笔记 -- 第四部分 Linux 使用着管理 -- 第14章 Linux 账号管理与ACL权限设置
- BZOJ 1015 星球大战starwar
- SharePoint 2013 自定义扩展菜单
- linux学习:增加user和sudo权限
- 【图】Dinic(n^2m)
- linux下.o、.a、.so文件解析
- Linux 学习笔记 -- 第四部分 Linux 使用着管理 -- 第15章 磁盘配额 (Quota) 与高级文件系统管理
- MongoDB学习笔记(一) MongoDB介绍及安装
- AMD+WIN8(64位)+VMware10安装MAC OS X10.6.3和Xcode3.2.2【详细】
- Qt5.3.0 for android windows平台下搭建及demo
- 可横屏左右滑动的GridView
- CListBox和CListCtrl练习之求素数
- Linux 学习笔记 -- 第四部分 Linux 使用着管理 -- 第16章 例行性工作 (crontab)