[Graph]网络流——Dinic
网络流.Dinic
定义:
源点:只有流出去的点
汇点:只有流进来的点
流量:一条边上流过的流量
容量:一条边上可供流过的最大流量
残量:一条边上的容量-流量
性质:
对于任何一条流,总有流量<=容量
∑p∈Ek[p][u]==∑q∈Ek[u][q](其中k[i][j]表示i到j的流量)
对于任何一条有向边有 k[u][v]=-k[v][u](k为流量)
网络最大流算法
基本思路:
找到一条从源点到汇点的路径,使得路径上任意一条边的残量>0,这条路径便称为增广路
找到这条路径上最小的F[u][v](我们设F[u][v]表示u->v这条边上的残量即剩余流量),下面记为flow
将这条路径上的每一条有向边u->v的残量减去flow,同时对于起反向边v->u的残量加上flow
重复上述过程,直到找不出增广路,此时我们就找到了最大流
反向边提供了反悔的机会,即万一这条路不是最优解,在下一次BFS时可以搜到这条反向边,返回原点。
Dinic的层次图为每个点提供了一个深度,加快了找到最大流的速度。
int bfs() { //cout<<"Bfs.begin:"<<endl; queue<int> Q; while (!Q.empty()) Q.pop(); memset(Depth,0,sizeof(Depth)); Depth[s]=1; Q.push(s); do { int u=Q.front(); //cout<<u<<endl; Q.pop(); for (int i=Head[u];i!=-1;i=Next[i]) { if ((W[i]>0)&&(Depth[V[i]]==0)) { Depth[V[i]]=Depth[u]+1; Q.push(V[i]); } } } while (!Q.empty()); //cout<<"Bfs.end"<<endl; if (Depth[t]>0) return 1; return 0; }
int dfs(int u,int dist) { //cout<<"Dfs:"<<u<<' '<<dist<<endl; if (u==t) return dist; for (int i=Head[u];i!=-1;i=Next[i]) { if ((Depth[V[i]]==Depth[u]+1)&&(W[i]!=0)) { int di=dfs(V[i],min(dist,W[i])); if (di>0) { W[i]-=di; W[i^1]+=di; return di; } } } return 0; }
#include<cstdio> #include<algorithm> #include<queue> #include<cstring> using namespace std; #define maxM 200010 #define maxN 100010 #define inf 2e9 int s,t; int cnt; int Head[maxM]; int Next[maxM]; int V[maxM]; int W[maxM]; int Depth[maxN]; int n; void init(int nn,int ss,int tt)//初始化 { n=nn; s=ss; t=tt; cnt=-1; memset(Head,-1,sizeof(Head)); memset(Next,-1,sizeof(Next)); return; } void _Add(int u,int v,int w) { cnt++; Next[cnt]=Head[u]; V[cnt]=v; W[cnt]=w; Head[u]=cnt; } void Add_Edge(int u,int v,int w)//加边,同时加正向和反向的 { _Add(u,v,w); _Add(v,u,0); } int dfs(int u,int dist) { //cout<<"Dfs:"<<u<<' '<<dist<<endl; if (u==t) return dist; for (int i=Head[u];i!=-1;i=Next[i]) { if ((Depth[V[i]]==Depth[u]+1)&&(W[i]!=0)) { int di=dfs(V[i],min(dist,W[i])); if (di>0) { W[i]-=di; W[i^1]+=di; return di; } } } return 0; } int bfs() { //cout<<"Bfs.begin:"<<endl; queue<int> Q; while (!Q.empty()) Q.pop(); memset(Depth,0,sizeof(Depth)); Depth[s]=1; Q.push(s); do { int u=Q.front(); //cout<<u<<endl; Q.pop(); for (int i=Head[u];i!=-1;i=Next[i]) { if ((W[i]>0)&&(Depth[V[i]]==0)) { Depth[V[i]]=Depth[u]+1; Q.push(V[i]); } } } while (!Q.empty()); //cout<<"Bfs.end"<<endl; if (Depth[t]>0) return 1; return 0; } int Dinic() { int Ans=0; while (bfs()) { while (int d=dfs(s,inf)) Ans+=d; } return Ans; } int main() { int num,i,bian,a,b,c,ss,tt; scanf("%d%d%d%d",&num,&bian,&ss,&tt); init(num,ss,tt); for(i=1;i<=bian;i++){ scanf("%d%d%d",&a,&b,&c); Add_Edge(a,b,c); } printf("%d",Dinic()); }