EK算法 时间复杂度o(n*m*m) 因为有反向边每次bfs时间为 n*m 每次删一条边 最多m次
代码
1 #include<iostream> 2 #include<string.h> 3 #include<vector> 4 #include<stdio.h> 5 #include<queue> 6 using namespace std; 7 const int maxn=2e5+10,inf=0x3f3f3f3f; 8 typedef long long ll; 9 struct edge 10 { 11 int from,to,c,f; 12 edge(int u,int v,int c,int f):from(u),to(v),c(c),f(f) {} 13 }; 14 int n,m; 15 vector<edge> edges; 16 vector<int> g[maxn]; 17 int a[maxn],p[maxn]; 18 void init() 19 { 20 for(int i=0; i<=n; i++) g[i].clear(); 21 edges.clear(); 22 } 23 void addedge(int from,int to,int c) 24 { 25 edges.push_back(edge(from,to,c,0)); 26 edges.push_back(edge(to,from,0,0)); 27 int siz=edges.size(); 28 g[from].push_back(siz-2); 29 g[to].push_back(siz-1); 30 } 31 ll maxflow(int s,int t) 32 { 33 ll flow=0; 34 while(1) 35 { 36 memset(a,0,sizeof(a)); 37 queue<int> q; 38 q.push(s); 39 a[s]=inf; 40 while(!q.empty()) 41 { 42 int x=q.front(); 43 q.pop(); 44 // cout<<x<<" "<<g[x].size()<<endl; 45 for(int i=0; i<g[x].size(); i++) 46 { 47 int u=g[x][i]; 48 edge &e=edges[u]; 49 //cout<<e.from<<" "<<e.to<<endl; 50 if(!a[e.to]&&e.c>e.f) 51 { 52 p[e.to]=u; //存边 53 a[e.to]=min(a[x],e.c-e.f); 54 q.push(e.to); 55 } 56 } 57 if(a[t])break; 58 } 59 // cout<<a[t]<<endl; //a[t]为一次增广值 60 if(!a[t]) break; 61 for(int u=t; u!=s; u=edges[p[u]].from)//流量修改 62 { 63 edges[p[u]].f+=a[t]; 64 edges[p[u]^1].f-=a[t]; 65 } 66 flow+=(ll)a[t]; 67 } 68 return flow; 69 } 70 int main() 71 { 72 int t,u,v,c,f,kase=1; 73 cin>>t; 74 while(t--) 75 { 76 cin>>n>>m; 77 init(); 78 for(int i=0; i<m; i++) 79 { 80 cin>>u>>v>>c; 81 addedge(u-1,v-1,c); 82 } 83 printf("Case %d: %d ",kase++,maxflow(0,n-1)); 84 //cout<<maxflow(0,n-1)<<endl; 85 } 86 }
Dinic 时间复杂度o(n*n*m)最多计算n-1次阻塞流 每次n*m 很松的上界
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e3+20,mod=1e9+7,inf=0x3f3f3f3f; 4 typedef long long ll; 5 struct edge 6 { 7 int from,to,c,f; 8 edge(int u,int v,int c,int f):from(u),to(v),c(c),f(f) {} 9 }; 10 int n,m; 11 vector<edge> edges; 12 vector<int> g[maxn]; 13 int d[maxn];//从起点到i的距离 14 int cur[maxn];//当前弧下标 15 void init() 16 { 17 for(int i=0; i<=n; i++) g[i].clear(); 18 edges.clear(); 19 } 20 void addedge(int from,int to,int c) //加边 支持重边 21 { 22 edges.push_back(edge(from,to,c,0)); 23 edges.push_back(edge(to,from,0,0)); 24 int siz=edges.size(); 25 g[from].push_back(siz-2); 26 g[to].push_back(siz-1); 27 } 28 int bfs(int s,int t) //构造一次层次图 29 { 30 memset(d,-1,sizeof(d)); 31 queue<int> q; 32 q.push(s); 33 d[s]=0; 34 while(!q.empty()) 35 { 36 int x=q.front();q.pop(); 37 for(int i=0;i<g[x].size();i++) 38 { 39 edge &e=edges[g[x][i]]; 40 if(d[e.to]<0&&e.f<e.c) //d[e.to]=-1表示没访问过 41 { 42 d[e.to]=d[x]+1; 43 q.push(e.to); 44 } 45 } 46 } 47 return d[t]; 48 } 49 int dfs(int x,int a,int t) // a表示x点能接收的量 50 { 51 if(x==t||a==0)return a; 52 int flow=0,f;//flow总的增量 f一条增广路的增量 53 for(int &i=cur[x];i<g[x].size();i++)//cur[i] &引用修改其值 从上次考虑的弧 54 { 55 edge &e=edges[g[x][i]]; 56 if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.c-e.f),t))>0) //按照层次图增广 满足容量限制 57 { 58 e.f+=f; 59 edges[g[x][i]^1].f-=f; //修改流量 60 flow+=f; 61 a-=f; 62 if(a==0) break; 63 } 64 } 65 return flow; 66 } 67 int maxflow(int s,int t) 68 { 69 int flow=0; 70 while(bfs(s,t)!=-1) //等于-1代表构造层次图失败 结束 71 { 72 memset(cur,0,sizeof(cur)); 73 flow+=dfs(s,inf,t); 74 } 75 return flow; 76 } 77 int main() 78 { 79 int t,kase=1; 80 scanf("%d",&t); 81 while(t--) 82 { 83 scanf("%d%d",&n,&m); 84 init(); 85 int u,v,c,f; 86 for(int i=0;i<m;i++) 87 { 88 scanf("%d%d%d",&u,&v,&c); 89 addedge(u,v,c); 90 } 91 printf("Case %d: %d ",kase++,maxflow(1,n)); 92 } 93 }
ISAP gap优化版 性能比dinic 好一点
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e3+20,mod=1e9+7,inf=0x3f3f3f3f; 4 typedef long long ll; 5 struct Edge 6 { 7 int from,to,cap,flow; 8 Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f) {} 9 }; 10 int n,m; 11 vector<Edge>edges; 12 vector<int>G[maxn]; 13 int vis[maxn]; 14 int d[maxn],cur[maxn]; 15 int p[maxn],num[maxn];//比Dinic算法多了这两个数组,p数组标记父亲结点,num数组标记距离d[i]存在几个 16 void init() 17 { 18 for(int i=0; i<=n; i++) G[i].clear(); 19 edges.clear(); 20 memset(d,-1,sizeof(d)); 21 } 22 void addedge(int from,int to,int cap) 23 { 24 edges.push_back(Edge(from,to,cap,0)); 25 edges.push_back(Edge(to,from,0,0)); 26 int m=edges.size(); 27 G[from].push_back(m-2); 28 G[to].push_back(m-1); 29 } 30 int Augumemt(int s,int t) 31 { 32 int x=t,a=inf; 33 while(x!=s)//找最小的残量值 34 { 35 Edge&e=edges[p[x]]; 36 a=min(a,e.cap-e.flow); 37 x=edges[p[x]].from; 38 } 39 x=t; 40 while(x!=s)//增广 41 { 42 edges[p[x]].flow+=a; 43 edges[p[x]^1].flow-=a;//更新反向边。 44 x=edges[p[x]].from; 45 } 46 return a; 47 } 48 void bfs(int t)//逆向进行bfs 49 { 50 memset(vis,0,sizeof(vis)); 51 queue<int>q; 52 q.push(t); 53 d[t]=0; 54 vis[t]=1; 55 while(!q.empty()) 56 { 57 int x=q.front(); 58 q.pop(); 59 int len=G[x].size(); 60 for(int i=0; i<len; i++) 61 { 62 Edge&e=edges[G[x][i]]; 63 if(!vis[e.from]&&e.cap>e.flow) 64 { 65 vis[e.from]=1; 66 d[e.from]=d[x]+1; 67 q.push(e.from); 68 } 69 } 70 } 71 } 72 73 int Maxflow(int s,int t)//根据情况前进或者后退,走到汇点时增广 74 { 75 int flow=0; 76 bfs(t); 77 memset(num,0,sizeof(num)); 78 for(int i=0; i<=n; i++) 79 num[d[i]]++; 80 int x=s; 81 memset(cur,0,sizeof(cur)); 82 while(d[s]<n) 83 { 84 if(x==t)//走到了汇点,进行增广 85 { 86 flow+=Augumemt(s,t); 87 x=s;//增广后回到源点 88 } 89 int ok=0; 90 for(int i=cur[x]; i<G[x].size(); i++) 91 { 92 Edge& e=edges[G[x][i]]; 93 if(e.cap>e.flow&&d[x]==d[e.to]+1) 94 { 95 ok=1; 96 p[e.to]=G[x][i];//记录来的时候走的边,即父边 97 cur[x]=i; 98 x=e.to;//前进 99 break; 100 } 101 } 102 if(!ok)//走不动了,撤退 103 { 104 int m=n-1;//如果没有弧,那么m+1就是n,即d[i]=n 105 for(int i=0; i<G[x].size(); i++) 106 { 107 Edge& e=edges[G[x][i]]; 108 if(e.cap>e.flow) 109 m=min(m,d[e.to]); 110 } 111 if(--num[d[x]]==0)break;//如果走不动了,且这个距离值原来只有一个,那么s-t不连通,这就是所谓的“gap优化” 112 num[d[x]=m+1]++; 113 cur[x]=0; 114 if(x!=s) 115 x=edges[p[x]].from;//退一步,沿着父边返回 116 } 117 } 118 return flow; 119 } 120 121 int main() 122 { 123 int t,kase=1; 124 scanf("%d",&t); 125 while(t--) 126 { 127 init(); 128 scanf("%d%d",&n,&m); 129 for(int i=0; i<m; i++) 130 { 131 int from,to,cap; 132 scanf("%d%d%d",&from,&to,&cap); 133 addedge(from,to,cap); 134 } 135 printf("Case %d: %d ",kase++,Maxflow(1,n)); 136 } 137 return 0; 138 }
ISAP算法 详解及其他版本参见https://blog.csdn.net/guhaiteng/article/details/52433239