Drainage Ditches
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 11306 Accepted Submission(s): 5328
Problem Description
Every time it rains on Farmer John‘s fields, a pond forms over Bessie‘s favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage
ditches so that Bessie‘s clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into
that ditch.
Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network.
Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle.
Input
The input includes several cases. For each case, the first line contains two space-separated integers, N (0 <= N <= 200) and M (2 <= M <= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections
points for those ditches. Intersection 1 is the pond. Intersection point M is the stream. Each of the following N lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei <= M) designate the intersections between which this ditch flows. Water
will flow through this ditch from Si to Ei. Ci (0 <= Ci <= 10,000,000) is the maximum rate at which water will flow through the ditch.
Output
For each case, output a single integer, the maximum rate at which water may emptied from the pond.
Sample Input
5 4 1 2 40 1 4 20 2 4 20 2 3 30 3 4 10
Sample Output
50
Source
题大意:给出边数N,点数M,每条边都是单向的,问从1点到M的最大流是多少。
方法一:ISAP
#include<stdio.h> #include<string.h> #include<queue> using namespace std; #define captype __int64 const int MAXN = 100010; const int MAXM = 400010; const int INF = 1<<30; struct EDG{ int to,next; captype cap,flow; } edg[MAXM]; int eid,head[MAXN]; int gap[MAXN]; //每种距离(或可认为是高度)点的个数 int dis[MAXN]; //每个点到终点eNode 的最短距离 int cur[MAXN]; //cur[u] 表示从u点出发可流经 cur[u] 号边 void init(){ eid=0; memset(head,-1,sizeof(head)); } //有向边 三个参数,无向边4个参数 void addEdg(int u,int v,captype c,captype rc=0){ edg[eid].to=v; edg[eid].next=head[u]; edg[eid].cap=c; edg[eid].flow=0; head[u]=eid++; edg[eid].to=u; edg[eid].next=head[v]; edg[eid].cap=rc; edg[eid].flow=0; head[v]=eid++; } //预处理eNode点到所有点的最短距离 void BFS(int sNode, int eNode){ queue<int>q; memset(gap,0,sizeof(gap)); memset(dis,-1,sizeof(dis)); gap[0]=1; dis[eNode]=0; q.push(eNode); while(!q.empty()){ int u=q.front(); q.pop(); for(int i=head[u]; i!=-1; i=edg[i].next){ int v=edg[i].to; if(dis[v]==-1){ dis[v]=dis[u]+1; gap[dis[v]]++; q.push(v); } } } } int S[MAXN]; //路径栈,存的是边的id号 captype maxFlow_sap(int sNode,int eNode, int n){ BFS(sNode, eNode); //预处理eNode到所有点的最短距离 if(dis[sNode]==-1) return 0; //源点到不可到达汇点 memcpy(cur,head,sizeof(head)); int top=0; //栈顶 captype ans=0; //最大流 int u=sNode; while(dis[sNode]<n){ //判断从sNode点有没有流向下一个相邻的点 if(u==eNode){ //找到一条可增流的路 captype Min=INF ; int inser; for(int i=0; i<top; i++) //从这条可增流的路找到最多可增的流量Min if(Min>edg[S[i]].cap-edg[S[i]].flow){ Min=edg[S[i]].cap-edg[S[i]].flow; inser=i; } for(int i=0; i<top; i++){ edg[S[i]].flow+=Min; edg[S[i]^1].flow-=Min; //可回流的边的流量 } ans+=Min; top=inser; //从这条可增流的路中的流量瓶颈 边的上一条边那里是可以再增流的,所以只从断流量瓶颈 边裁断 u=edg[S[top]^1].to; //流量瓶颈 边的起始点 continue; } bool flag = false; //判断能否从u点出发可往相邻点流 int v; for(int i=cur[u]; i!=-1; i=edg[i].next){ v=edg[i].to; if(edg[i].cap-edg[i].flow>0 && dis[u]==dis[v]+1){ flag=true; cur[u]=i; break; } } if(flag){ S[top++] = cur[u]; //加入一条边 u=v; continue; } //如果上面没有找到一个可流的相邻点,则改变出发点u的距离(也可认为是高度)为相邻可流点的最小距离+1 int Mind= n; for(int i=head[u]; i!=-1; i=edg[i].next){ if(edg[i].cap-edg[i].flow>0 && Mind>dis[edg[i].to]){ Mind=dis[edg[i].to]; cur[u]=i; }} gap[dis[u]]--; if(gap[dis[u]]==0) return ans; //当dis[u]这种距离的点没有了,也就不可能从源点出发找到一条增广流路径 //因为汇点到当前点的距离只有一种,那么从源点到汇点必然经过当前点,然而当前点又没能找到可流向的点,那么必然断流 dis[u]=Mind+1; //如果找到一个可流的相邻点,则距离为相邻点距离+1,如果找不到,则为n+1 gap[dis[u]]++; if(u!=sNode) u=edg[S[--top]^1].to; //退一条边 } return ans; } int main(){ int n,m,u,v; captype c; while(scanf("%d%d",&m,&n)>0){ init(); while(m--){ scanf("%d%d%I64d",&u,&v,&c); addEdg(u,v,c); } printf("%I64d\n",maxFlow_sap(1,n,n)); } }
方法二:压入重标记push_relabel
#include<stdio.h> #include<string.h> #include<queue> using namespace std; #define captype __int64 const int N = 210; const int MAX= 1<<30; struct EDG{ int to,nxt; captype c; //每条边的残留量 }edg[N*N]; int head[N],eid; captype vf[N]; //顶点的剩余流量 int h[N]; //顶点的高度 //int n; //顶点个总个数,包含源点与汇点 int min(int a,int b){return a>b?b:a; } void init(){ memset(head,-1,sizeof(head)); eid=0; } //添加 有向边 void addEdg(int u , int v, captype c){ edg[eid].to=v; edg[eid].nxt=head[u]; edg[eid].c=c; head[u]=eid++; edg[eid].to=u; edg[eid].nxt=head[v]; edg[eid].c=0; head[v]=eid++; } captype maxFlow(int sNode,int eNode,int n){//源点与汇点 captype minh,ans=0; queue<int>q; memset(h,0,sizeof(h)); memset(vf,0,sizeof(vf)); h[sNode]=n+1; //源点的高度 vf[sNode]=MAX; //源点的余流 q.push(sNode); while(!q.empty()){ int u=q.front(); q.pop(); minh=MAX; for(int i=head[u]; i!=-1; i=edg[i].nxt){ int v=edg[i].to; captype fp; if(edg[i].c<vf[u])fp=edg[i].c; else fp=vf[u]; if(fp>0 ){ minh=min(minh, h[v]); if(u==sNode || h[u]==h[v]+1){ edg[i].c-=fp; edg[i^1].c+=fp; //反向边,给个反回的通道 vf[u]-=fp; vf[v]+=fp; if(v==eNode) ans+=fp; //当到达汇点时,就加入最大流中 if(v!=sNode && v!=eNode ) //只有即不是源点,也不是汇点时才能进队列 q.push(v); } } if(vf[u]==0) break; //如果顶点的余流为0,则可以跳出for循环 } //如果不是源点(也非汇点),且顶点仍有余流,则重新标记 高度+1 入队 //这里赋值为最低的相邻顶点的高度高一个单位,也可以简单的在原高度+1 if(u!=sNode && vf[u]>0){ h[u] = minh + 1; q.push(u); } } return ans; } int main(){ int n,m,u,v; captype c; while(scanf("%d%d",&m,&n)>0){ init(); while(m--){ scanf("%d%d%I64d",&u,&v,&c); addEdg(u,v,c); } printf("%I64d\n",maxFlow(1,n,n)); } }
方法三:EK
#include<stdio.h> #include<string.h> #include<queue> using namespace std; #define captype __int64 const int N = 205; captype cap[N][N],f[N][N],rest[N]; int sNode,eNode,pre[N]; void init(){ memset(f,0,sizeof(f)); memset(cap,0,sizeof(cap)); } bool searchPath(int n){//找一条增广路 bool vist[N]={0}; queue<int>q; int u,v; u=sNode; vist[u]=1; pre[u]=u; rest[u]=1<<30; q.push(u); while(!q.empty()){ u=q.front(); q.pop(); for(v=1; v<=n; v++) if(!vist[v]&&cap[u][v]-f[u][v]>0) { vist[v]=1; pre[v]=u; if(cap[u][v]-f[u][v]>rest[u]) rest[v]=rest[u]; else rest[v]=cap[u][v]-f[u][v]; if(v==eNode) return true; q.push(v); } } return false; } captype maxflow(int s,int t,int n){ captype ans=0; sNode=s; eNode=t; while(searchPath(n)){ ans+=rest[eNode]; int v=eNode; while(v!=sNode){ int u=pre[v]; f[u][v]+=rest[eNode]; f[v][u]-=rest[eNode];//给一个回流的机会 v=u; } } return ans; } int main(){ int n,m,u,v; captype c; while(scanf("%d%d",&m,&n)>0){ init(); while(m--){ scanf("%d%d%I64d",&u,&v,&c); cap[u][v]+=c; } printf("%I64d\n",maxflow(1,n,n)); } }