最大流 Dinic演算法
阿新 • • 發佈:2018-12-03
Dinic演算法模板
鄰接矩陣形式
#include<iostream> #include<cstring> #include<algorithm> #include<queue> #include<vector> using namespace std; const int N=205; const int INF=0x3f3f3f3f; int g[N][N],layer[N]; bool vis[N]; int n,m;//1是源點 n是匯點 bool CounterLayer() { queue<int>q; memset(layer,-1,sizeof(layer)); layer[1]=0; q.push(1); while(!q.empty()) { int v=q.front(); q.pop(); for(int i=1;i<=n;i++) if(g[v][i]>0&&layer[i]==-1) { layer[i]=layer[v]+1; if(i==n)//分層到匯點即可 return true; else q.push(i); } } return false; } int Dinic() { int ans=0; vector<int>q; while(CounterLayer())//只要能分層 { q.push_back(1);//源點入棧 while(!q.empty()) { int u=q.back(); if(u==n)//如果u是匯點,在路徑中找容量最小邊 { int temp=INF; int st;//容量最小邊的起點 for(int i=1;i<q.size();i++) { int vs=q[i-1]; int ve=q[i]; if(g[vs][ve]>0&&temp>g[vs][ve]) temp=g[st=vs][ve]; } //改圖 ans+=temp; for(int i=1;i<q.size();i++) { int vs=q[i-1]; int ve=q[i]; g[vs][ve]-=temp; g[ve][vs]+=temp; } //退棧到 st 成為棧頂,以便繼續dfs while(!q.empty()&&q.back()!=st) q.pop_back(); } else//如果u不是匯點 { int i; for(i=1;i<=n;i++)//往下一層結點走 if(g[u][i]>0&&layer[i]==layer[u]+1) { q.push_back(i); break; } if(i>n)//找不到下一個結點 { layer[q.back()]=-1; q.pop_back(); } } } } return ans; } int main() { while(~scanf("%d%d",&m,&n)) { int s,e,c; memset(g,0,sizeof(g)); for(int i=1;i<=m;i++) { scanf("%d%d%d",&s,&e,&c); g[s][e]+=c; } printf("%d\n",Dinic()); } return 0; }
鄰接表形式(前向星實現)
#include<iostream> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int N=205; const int INF=0x3f3f3f3f; int layer[N]; bool vis[N]; int n,m;//1是源點 n是匯點 //前向星實現鄰接表 int M; int head[N]; struct Edge{ int from,to,next,w; }edge[N*N]; void add(int from,int to,int w) { edge[M].next=head[from]; edge[M].to=to; edge[M].w=w; head[from]=M++; } bool CountLayer()//分層 { queue<int>q; memset(layer,-1,sizeof(layer)); layer[1]=0; q.push(1); while(!q.empty()) { int u=q.front(); q.pop(); for(int k=head[u];k!=-1;k=edge[k].next) { int v=edge[k].to; int w=edge[k].w; if(w>0&&layer[v]==-1) { layer[v]=layer[u]+1; if(v==n) return true; else q.push(v); } } } return false; } int Dinic(int s,int t) { int ans=0; int q[N*N]; while(CountLayer()) { int k,u,v,back,size=1; while(size) { u=(size==1)?s:edge[q[size-1]].to; //u是匯點 if(u==t) { int temp=INF; for(int i=1;i<size;i++) { k=q[i]; if(edge[k].w>0&&edge[k].w<temp) { temp=edge[k].w; back=i; } } //改圖 for(int i=1;i<size;i++) { k=q[i]; edge[k].w-=temp; edge[k^1].w+=temp; } ans+=temp; size=back; } //u不是匯點 else { for(k=head[u];k!=-1;k=edge[k].next) { int v=edge[k].to; if(edge[k].w>0&&layer[v]==layer[u]+1) break; } if(k!=-1) q[size++]=k; else { layer[u]=-1; size--; } } } } return ans; } int main() { while(~scanf("%d%d",&m,&n)) { int s,e,c; M=0; memset(head,-1,sizeof(head)); for(int i=1;i<=m;i++) { scanf("%d%d%d",&s,&e,&c); add(s,e,c); add(e,s,0);//新增反向邊 } printf("%d\n",Dinic(1,n)); } return 0; }