//洛谷P3376
对于最大流是什么,各位可以Baidu一下,简而言之,就是求一个有向图中,从源点(S)到汇点(T)流量(Flow)的最大流通量。
而对于这个方案的求解,我们肯定首先想到的是按照上面这三个原理进行贪心......
然后一顿贪心以后,发现找的的不一定是最优解,因为,有时。
所以我们引进Dinic算法:
- 在建图的时候,我们建立一条反向边,并用e[i^1]去存(想一想为什么)
struct edge{ int to,flow; }e[N*2]; int fst[N],nxt[N],cnt; void addedge(int x,int y,int f){ e[cnt]=(edge){y,f}; nxt[cnt]=fst[x],fst[x]=cnt++; e[cnt]=(edge){x,0}; nxt[cnt]=fst[y],fst[y]=cnt++; }
- 然后开始搜索
- 首先是Bfs:
- 从S开始,逐渐Bfs,把没有分层的点分成layer[x]+1再压入队列
- 若T已被分层,则代表原图有增广路
- 否则则原图已经没有增广路,已经是最优解
- 然后是Dfs
- 逐渐增广以致最优解
简而言之一句话:while(Bfs()) dfs();
最后是代码(数组邻接表格式):
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<queue> #define _int long long #define N 200000 + 10 #define INF 2147483647 using namespace std; struct edge{ int to,flow; }e[N*2]; int n,m,S,T; int fst[N],nxt[N],cnt; int layer[N]; void addedge(int x,int y,int f){ e[cnt]=(edge){y,f}; nxt[cnt]=fst[x],fst[x]=cnt++; e[cnt]=(edge){x,0}; nxt[cnt]=fst[y],fst[y]=cnt++; } bool bfs(){ memset(layer,-1,sizeof(layer)); queue<int> que; que.push(S); layer[S]=0; while(!que.empty()){ int x=que.front();que.pop(); for(int i=fst[x];i!=-1;i=nxt[i]){ if(layer[e[i].to]==-1&&e[i].flow>0){ layer[e[i].to]=layer[x]+1; que.push(e[i].to); } } } if(layer[T]<=0) return false; else return true; } int dfs(int u,int v,int f){ if(u==v || f==0) return f; for(int i=fst[u];i!=-1;i=nxt[i]){ if(e[i].flow>0&&layer[e[i].to]==layer[u]+1){ int d=dfs(e[i].to,v,min(f,e[i].flow)); if(d>0){ e[i].flow-=d; e[i^1].flow+=d; return d; } } } } int Dinic(){ int f=0; while(bfs()) f+=dfs(S,T,INF); return f; } int main(){ scanf("%d%d%d%d",&n,&m,&S,&T); memset(fst,-1,sizeof(fst)); memset(nxt,-1,sizeof(nxt)); for(int i=0;i<m;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); } printf("%d",Dinic()); return 0; }