P3376 【模板】网络最大流
EK算法 (个人感觉没有dinic好理解)
1 //Edmonds-Karp算法 2 //时间复杂度o(n*m*m) 3 #include<iostream> 4 #include<cstdio> 5 #include<cstring> 6 #include<algorithm> 7 #include<queue> 8 using namespace std; 9 10 const int N=10005; 11 const int M=100005; 12 const int INF=599518803; 13 14 int n,m,s,t; 15 int num_edge,head[N]; 16 int val[N],pre[N]; 17 struct Edge 18 { 19 int u,v,w,flow,nxt; 20 }edge[M<<1]; 21 22 int read() 23 { 24 int num=0;char c=getchar(); 25 for(;!isdigit(c);c=getchar()); 26 for(;isdigit(c);c=getchar()) 27 num=num*10+c-'0'; 28 return num; 29 } 30 31 void add_edge(int u,int v,int w) 32 { 33 edge[++num_edge].u=u; 34 edge[num_edge].v=v; 35 edge[num_edge].w=w; 36 edge[num_edge].nxt=head[u]; 37 head[u]=num_edge; 38 } 39 40 bool bfs() 41 { 42 memset(val,0,sizeof(val)); 43 memset(pre,0,sizeof(pre)); 44 queue<int> que; 45 val[s]=INF;//假设起点的可以的剩余流量无限大 46 pre[s]=0;//储存上一个节点 47 int now,v; 48 que.push(s); 49 while(!que.empty()) 50 { 51 now=que.front(),que.pop(); 52 for(int i=head[now];i;i=edge[i].nxt) 53 { 54 v=edge[i].v; 55 if(!val[v]&&edge[i].w>edge[i].flow)//如果没有经过并且容量大于流量 56 { 57 que.push(v); 58 val[v]=min(val[now],edge[i].w-edge[i].flow);//剩余流量等于前一个节点的剩余流量与这条路的剩余流量的最小值 59 pre[v]=i; 60 } 61 if(val[t])//循环到了t就跳出循环 62 break; 63 } 64 } 65 return val[t]; 66 } 67 68 int main() 69 { 70 n=read(),m=read(),s=read(),t=read(); 71 num_edge=1; 72 for(int i=1,u,v,w;i<=m;++i) 73 { 74 u=read(),v=read(),w=read(); 75 add_edge(u,v,w); 76 add_edge(v,u,0); 77 } 78 int ans=0; 79 while(bfs()) 80 { 81 for(int i=t;i!=s;i=edge[pre[i]].u) 82 { 83 edge[pre[i]].flow+=val[t]; 84 edge[pre[i]^1].w-=val[t]; 85 } 86 ans+=val[t]; 87 } 88 printf("%lld",ans); 89 return 0; 90 }
dinic详解blog:http://www.cnblogs.com/LUO77/p/6115057.html
//Dinic //快忘干净了 //写一下自己能想起来的地 //改了几遍,差不多可以想起来了,而且也明白了一些以前没明白的地方 //emmm,在改进代码中加强对代码的理解程度吧算是 //开了氧气之后可以跑到72ms啦! //要一开始让num_edge=1,感觉可能会因为忘写翻车 #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int N=1e4+5; const int M=1e5+5; int n,m,s,t; int head[N],from[N],num_edge; int dep[N]; struct Edge { int v,flow,nxt; }edge[M<<1]; inline int read() { char c=getchar();int num=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num; } inline void add_edge(int u,int v,int w) { edge[++num_edge].v=v; edge[num_edge].flow=w; edge[num_edge].nxt=head[u]; head[u]=num_edge; } inline bool bfs() { for(int i=1;i<=n;++i) //当前弧用到的 from[i]=head[i],dep[i]=0; queue<int> que; dep[s]=1,que.push(s); int now,v; while(!que.empty()) { now=que.front(),que.pop(); for(int i=head[now];i;i=edge[i].nxt) { v=edge[i].v; if(!dep[v]&&edge[i].flow) { dep[v]=dep[now]+1; if(v==t) //到达汇点了,直接return return 1; que.push(v); } } } return 0; } int dfs(int now,int flow) { if(now==t||!flow) return flow; int outflow=0,tmp; for(int &i=from[now],v;i;i=edge[i].nxt) //只有满流之后才会换边,不满流不换边 { v=edge[i].v; if(dep[v]!=dep[now]+1) continue; tmp=dfs(v,min(flow,edge[i].flow)); flow-=tmp; outflow+=tmp; //又流出去了些流量 edge[i].flow-=tmp; //当前边的流量- edge[i^1].flow+=tmp; //反向弧的流量+ if(!flow) //把从上边传下来的流量全都流完了,直接return,但是不要换边! return outflow; } dep[now]=0; //能从for循环里出来而没有提前return说明这个点所连出去的边流量全都流完了(全都满流),所以把这个点的dep设成0,他已经没有贡献了 return outflow; } int main() { n=read(),m=read(),s=read(),t=read(); num_edge=1; for(int i=1,u,v,w;i<=m;++i) { u=read(),v=read(),w=read(); add_edge(u,v,w); add_edge(v,u,0); } int ans=0; while(bfs()) ans+=dfs(s,0x7fffffff); printf("%d",ans); return 0; }