1993 草地排水
题目描述 Description
在农夫约翰的农场上,每逢下雨,Bessie最喜欢的三叶草地就积聚了一潭水。这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间。因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没的烦恼(不用担心,雨水会流向附近的一条小溪)。作为一名一流的技师,农夫约翰已经在每条排水沟的一端安上了控制器,这样他可以控制流入排水沟的水流量。
农夫约翰知道每一条排水沟每分钟可以流过的水量,和排水系统的准确布局(起点为水潭而终点为小溪的一张网)。需要注意的是,有些时候从一处到另一处不只有一条排水沟。
根据这些信息,计算从水潭排水到小溪的最大流量。对于给出的每条排水沟,雨水只能沿着一个方向流动,注意可能会出现雨水环形流动的情形。
输入描述 Input Description
第1行: 两个用空格分开的整数N (0 <= N <= 200) 和 M (2 <= M <= 200)。N是农夫John已经挖好的排水沟的数量,M是排水沟交叉点的数量。交点1是水潭,交点M是小溪。
第二行到第N+1行: 每行有三个整数,Si, Ei, 和 Ci。Si 和 Ei (1 <= Si, Ei <= M) 指明排水沟两端的交点,雨水从Si 流向Ei。Ci (0 <= Ci <= 10,000,000)是这条排水沟的最大容量。
输出描述 Output Description
输出一个整数,即排水的最大流量。
样例输入 Sample Input
5 4 1 2 40 1 4 20 2 4 20 2 3 30 3 4 10
样例输出 Sample Output
50
这是一道最大流的经典题
最大流尽量应该用边表,优于邻接矩阵(所以我写了邻接矩阵版的之后又写了个边表)
用了新学的Dinic算法
在每次找增广路之前先跑一遍bfs,把所有点的深度标记,按bfs记下的顺序找增广路,这条增广路上最小的边容量就是这条增广路的最大费用
跑出一条增广路之后,就开始更新现在的边剩余的容量,并建立反向边。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; int n,m,map[300][300],ans,pre[300]; void Flow(int s,int t){ while(1){ queue<int>q; q.push(1); memset(pre,0,sizeof(pre)); while(!q.empty()){ int point=q.front(); q.pop();if(point==t)break; for(int i=1;i<=n;i++){ if(map[point][i]&&!pre[i])pre[i]=point,q.push(i); } }if(pre[t]==0)break; int so=0x7fffffff; for(int i=t;i!=s;i=pre[i]){ so=min(so,map[pre[i]][i]); }ans+=so; for(int i=t;i!=s;i=pre[i]){ map[i][pre[i]]+=so; map[pre[i]][i]-=so; } } } int main(){ while(scanf("%d%d",&m,&n)!=EOF){ int f,t,v; memset(map,0,sizeof(map)); for(int i=1;i<=m;i++){ scanf("%d%d%d",&f,&t,&v); map[f][t]+=v; } ans=0; Flow(1,n); printf("%d\n",ans); } }
邻接矩阵
#include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; #define inf 100000000 struct node{ int to,v,p; }e[300]; int ans,n,m,num=1,head[300]; void add(int from,int to,int v){ e[++num].to=to; e[num].v=v; e[num].p=head[from]; head[from]=num; } int dep[300],road[300],NUM; bool bfs(){ queue<int>q; memset(dep,127/3,sizeof(dep)); q.push(1); dep[1]=0; while(!q.empty()){ int point=q.front();q.pop(); for(int i=head[point];i;i=e[i].p){ if(e[i].v&&dep[e[i].to]>dep[point]+1){ dep[e[i].to]=dep[point]+1; if(e[i].to==n)return true; q.push(e[i].to); } } } return false; } int dinic(int s,int f){ if(s==n)return f; int rest=f; for(int i=head[s];i;i=e[i].p){ if(e[i].v&&dep[e[i].to]==dep[s]+1&&rest){ int t=dinic(e[i].to,min(rest,e[i].v)); if(!t)dep[e[i].to]=0; e[i].v-=t; e[i^1].v+=t; rest-=t; } } return f-rest; } int main(){ scanf("%d%d",&m,&n); int f,t,v; for(int i=1;i<=m;i++){ scanf("%d%d%d",&f,&t,&v); add(f,t,v); add(t,f,0); } while(bfs()) ans+=dinic(1,inf); printf("%d",ans); }
边表