Ford-Fulkson用EK实现:483ms
#include <cstdio> #include <cstring> #define min(x,y) (x>y?y:x) int pre[105],q[105]; int F[105][105]; int n,nc,np,m,s,t,all; int MaxFlow(int s, int t){ int ans=0; while(1){ memset(pre,0,sizeof(pre)); int head=0,tail=0; q[++tail]=s; while(head<tail&&pre[t]==0){ int cur=q[++head]; for(int i=1; i<=n; i++) if(F[cur][i]>0&&pre[i]==0){ pre[i]=cur; q[++tail]=i; } } if(pre[t]==0) break; int minF=100000000; for(int i=t; i!=s; i=pre[i]) minF=min(minF,F[pre[i]][i]); for(int i=t; i!=s; i=pre[i]) { F[pre[i]][i]-=minF; F[i][pre[i]]+=minF; } ans+=minF; } return ans; } int main() { int x,y,z; while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF){ all=0; memset(F,0,sizeof(F)); s=n+1; t=n+2; n=n+2; for(int i=0; i<m; i++){ while(getchar()!='(') ; scanf("%d,%d)%d",&x,&y,&z); F[x+1][y+1]=z; } for(int i=0; i<np; i++){ while(getchar()!='(') ; scanf("%d)%d",&x,&z); F[s][x+1]=z; } for(int i=0; i<nc; i++){ while(getchar()!='(') ; scanf("%d)%d",&x,&z); F[x+1][t]=z; } printf("%d\n",MaxFlow(s,t)); } return 0; }
Dinic用DFS实现:360ms
#include <cstdio> #include <cstring> #define min(x,y) ((x)>(y)?(y):(x)) #define N 105 #define M 10005 int n,np,nc,m,all,s,t; int d[N],be[N]; struct Edge{ int x,y,c,next; }e[M*2]; void add(int x, int y, int z)//需保证相反边第一个为偶数 { e[all].x=x; e[all].y=y; e[all].c=z; e[all].next=be[x]; be[x]=all; all++; e[all].x=y; e[all].y=x; e[all].c=0; e[all].next=be[y]; be[y]=all; all++; } bool BFS(int s, int t) { memset(d,-1,sizeof(d)); int head=0,tail=0,q[N]; q[++tail]=s; d[s]=0; while(head<tail){ int cur=q[++head]; for(int i=be[cur]; i!=-1; i=e[i].next) if(e[i].c>0 && d[e[i].y]==-1){ d[e[i].y]=d[cur]+1; q[++tail]=e[i].y; } } return d[t]!=-1; } int DFS(int cur, int minc) { if(cur==t) return minc;//表示路径上该点前方最小容量 int ans=0,tmp;//ans表示该点要增大的流 for(int i=be[cur]; i!=-1; i=e[i].next) if(e[i].c>0 && d[e[i].y]==d[cur]+1 && (tmp=DFS(e[i].y,min(minc-ans,e[i].c))))//多路增广很快 因为不用返回到s 容易证明能保证minc>0 { e[i].c-=tmp; e[i^1].c+=tmp; ans+=tmp; } if(ans==0) d[cur]=-1;//关键的一句话 否则超时 用于多路增广 return ans; } int Dinic(int s, int t) { int ans=0,tmp; while(BFS(s,t)){ while(tmp=DFS(s,1000000000)) ans+=tmp; } return ans; } int main() { int x,y,z; while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF){ all=0; memset(be,-1,sizeof(be)); s=n; t=n+1; n=n+2; for(int i=0; i<m; i++){ while(getchar()!='(') ; scanf("%d,%d)%d",&x,&y,&z); add(x,y,z); } for(int i=0; i<np; i++){ while(getchar()!='(') ; scanf("%d)%d",&x,&z); add(s,x,z); } for(int i=0; i<nc; i++){ while(getchar()!='(') ; scanf("%d)%d",&x,&z); add(x,t,z); } printf("%d\n",Dinic(s,t)); } return 0; }
Dinic用栈模拟递归实现:63ms
#include <cstdio> #include <cstring> #define min(x,y) ((x)>(y)?(y):(x)) #define N 105 #define M 10005 int n,np,nc,m,all,s,t; int d[N],be[N]; struct Edge{ int x,y,c,next; }e[M*2]; void add(int x, int y, int z)//需保证相反边第一个为偶数 { e[all].x=x; e[all].y=y; e[all].c=z; e[all].next=be[x]; be[x]=all; all++; e[all].x=y; e[all].y=x; e[all].c=0; e[all].next=be[y]; be[y]=all; all++; } bool BFS(int s, int t) { memset(d,-1,sizeof(d)); int head=0,tail=0,q[N]; q[++tail]=s; d[s]=0; while(head<tail){ int cur=q[++head]; for(int i=be[cur]; i!=-1; i=e[i].next) if(e[i].c>0 && d[e[i].y]==-1){ d[e[i].y]=d[cur]+1; q[++tail]=e[i].y; } } return d[t]!=-1; } int Dinic(int s, int t)//防止爆栈 用stack模拟递归 { int ans=0; int stack[N],top; int begin[N]; while(BFS(s,t)) { memcpy(begin,be,sizeof(be)); int cur=s; top=0;//dfs开始 清空栈 while(1) { if(cur==t){ int minc=1000000000,mini; for(int i=0; i<top; i++) if(minc>e[stack[i]].c) { minc=e[stack[i]].c; mini=i;//以便之后回到这继续增广 } for(int i=0; i<top; i++) { e[stack[i]].c-=minc; e[stack[i]^1].c+=minc;//第一个二进制取反 即取相反边 } ans+=minc; top=mini; cur=e[stack[mini]].x; } for(int i=begin[cur]; i!=-1; begin[cur]=i=e[begin[cur]].next) if(e[i].c>0 && d[e[i].y]==d[e[i].x]+1) break; if(begin[cur]!=-1){ stack[top++]=begin[cur]; cur=e[begin[cur]].y; }else{ if(top==0) break; d[cur]=-1;//当前节点不在增广路中 删除 cur=e[stack[--top]].x;//回溯 } } } return ans; } int main() { int x,y,z; while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF){ all=0; memset(be,-1,sizeof(be)); s=n; t=n+1; n=n+2; for(int i=0; i<m; i++){ while(getchar()!='(') ; scanf("%d,%d)%d",&x,&y,&z); add(x,y,z); } for(int i=0; i<np; i++){ while(getchar()!='(') ; scanf("%d)%d",&x,&z); add(s,x,z); } for(int i=0; i<nc; i++){ while(getchar()!='(') ; scanf("%d)%d",&x,&z); add(x,t,z); } printf("%d\n",Dinic(s,t)); } return 0; }