题目大意:m个池塘,n条水渠(单向导通),池塘从1到m编号,1号是源点,m号是汇点,。已知各条水渠的最大输送水的速率,求单位时间内流经m号池塘的最大流量。
法一:Edmonds-Karp算法
该算法是通过BFS来寻找从源点到汇点的增广路径,不断更新残留网络来求出最大流。
有关该算法的详解:Edmonds-Karp算法详解
其时间复杂度为O(NM^2)
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<queue> #include<stack> #include<map> #include<set> #include<cstdlib> using namespace std; #define mod 1000000007 typedef __int64 LL; int Cap[205][205],n,m,vis[205],p[205]; int EKarp(int s,int e) { int ans=0,u,mn; while(true){ memset(p,-1,sizeof(p)); memset(vis,0,sizeof(vis)); vis[s]=1; queue<int> q; q.push(s); bool flag=0; while(!q.empty()){ u=q.front(); if(u==e) {flag=1;break;} q.pop(); for(int i=1;i<=m;++i){ if(Cap[u][i]&&!vis[i]){ vis[i]=1; q.push(i); p[i]=u; } } } if(!flag) break; mn=0x3f3f3f3f,u=e; while(~p[u]){ mn=min(mn,Cap[p[u]][u]); u=p[u]; } ans+=mn; u=e; while(~p[u]){ Cap[p[u]][u]-=mn; Cap[u][p[u]]+=mn; u=p[u]; } } return ans; } int main() { int i,a,b,c; while(~scanf("%d%d",&n,&m)) { memset(Cap,0,sizeof(Cap)); for(i=1;i<=n;++i){ scanf("%d%d%d",&a,&b,&c); Cap[a][b]+=c; } printf("%d\n",EKarp(1,m)); } return 0; }
法二:Dinic算法
该算法是通过BFS构造出层次图,然后依次从每一层寻找增广路(这样可同时对多条路径进行增广),对增广路中的所有边进行阻塞,所谓阻塞,个人理解其实就是找出每条增广路中流量最少的那条边,然后该路径上的所有边的流量都减去该流量,可行流量增加该流量。容易理解,这样可以在保证不超过流量限制的条件下,使得增加的流量达到最大。
详解见大白书P358-360
关于递归的Dinic
时间复杂度为O(N^2*M)
#include<iostream> #include<cstdio> #include<cmath> #include<map> #include<set> #include<algorithm> #include<queue> #include<stack> #include<cstdlib> #include<cstring> #include<vector> using namespace std; typedef long long LL; typedef double db; #define maxn 205 #define maxm 205 #define inf 0x3f3f3f3f struct Edge{ int to,next,cap; }edge[maxm<<1]; int n,m,s,t; //结点数、边数(含反向弧)、源点、汇点 int cnt,head[maxn]; int d[maxn]; //层次 inline void add(int u,int v,int cap){ edge[cnt].to=v; edge[cnt].cap=cap; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].to=u; edge[cnt].cap=0; edge[cnt].next=head[v]; head[v]=cnt++; } inline bool bfs(){ memset(d,0,sizeof(d)); queue<int>Q; Q.push(s); d[s]=1; while(!Q.empty()){ int u=Q.front();Q.pop(); for(int i=head[u];~i;i=edge[i].next){ int v=edge[i].to; if(!d[v]&&edge[i].cap){ d[v]=d[u]+1; Q.push(v); } } } return d[t]; } int dfs(int x,int a){ //当前结点,目前为止所有弧的最小残量 if(x==t) return a; int f; for(int i=head[x];~i;i=edge[i].next){ int v=edge[i].to; if(d[x]+1==d[v]&&(f=dfs(v,min(a,edge[i].cap)))) { edge[i].cap-=f; edge[i^1].cap+=f; return f; } } return 0; } int dinic(){ int flow=0; while(bfs()) flow+=dfs(s,inf); return flow; } int main() { int a,b,c; while(~scanf("%d%d",&m,&n)){ memset(head,-1,sizeof(head)); cnt=0,s=1,t=n; for(int i=0;i<m;++i){ scanf("%d%d%d",&a,&b,&c); add(a,b,c); } printf("%d\n",dinic()); } return 0; }
法三:ISAP
详解:点击打开链接
#include<iostream> #include<cstdio> #include<cmath> #include<map> #include<set> #include<algorithm> #include<queue> #include<stack> #include<cstdlib> #include<cstring> #include<vector> #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; typedef long long LL; typedef unsigned long long uLL; typedef unsigned int uI; typedef double db; #define maxn 100005 #define inf 0x3f3f3f3f #define maxm 200005 #define maxq 100005 struct Edge{ int to,cap,next; }edge[maxm]; int Q[maxq],qhead,tail;//队列 int cnt,head[maxn],d[maxn],cur[maxn],pre[maxn],num[maxn]; int sourse,sink,nv;//源点、汇点、编号修改的上限 int n,m; inline void add(int u,int v,int w) { edge[cnt].to=v; edge[cnt].cap=w; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].to=u; edge[cnt].cap=0; edge[cnt].next=head[v]; head[v]=cnt++; } void bfs() { memset(num,0,sizeof(num)); memset(d,-1,sizeof(d)); d[sink]=0; num[0]=1; qhead=tail=0; Q[tail++]=sink; while(qhead!=tail) { int u=Q[qhead++]; for(int i=head[u];~i;i=edge[i].next) { int v=edge[i].to; if(~d[v]) continue; d[v]=d[u]+1; Q[tail++]=v; num[d[v]]++; } } } int ISAP() { int i; for(i=0;i<=n;++i) cur[i]=head[i]; bfs(); int flow=0,u=pre[sourse]=sourse; while(d[sink]<nv) { if(u==sink) { int f=inf,neck; for(i=sourse;i!=sink;i=edge[cur[i]].to) { if(f>edge[cur[i]].cap) { f=edge[cur[i]].cap; neck=i; } } for(i=sourse;i!=sink;i=edge[cur[i]].to) { edge[cur[i]].cap-=f; edge[cur[i]^1].cap+=f; } flow+=f; u=neck; } for(i=cur[u];~i;i=edge[i].next) if(d[edge[i].to]+1==d[u]&&edge[i].cap) break; if(~i) { cur[u]=i; pre[edge[i].to]=u; u=edge[i].to; } else{ if(0==(--num[d[u]])) break; int mind=nv; for(i=head[u];~i;i=edge[i].next) { if(edge[i].cap&&mind>d[edge[i].to]) { cur[u]=i; mind=d[edge[i].to]; } } d[u]=mind+1; num[d[u]]++; u=pre[u]; } } return flow; } int main() { while(~scanf("%d%d",&m,&n)) { memset(head,-1,sizeof(head)); cnt=0; sourse=1,sink=n,nv=sink+1; for(int i=0;i<m;++i) { int a,b,c; scanf("%d%d%d",&a,&b,&c); add(a,b,c); } printf("%d\n",ISAP()); } return 0; }