【codevs 1993】草地排水(最大流)
1993 草地排水
时间限制:
2 s空间限制: 256000 KB 题目等级 : 钻石 Diamon
题目描述 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
【题解】【网络流最大流模板题】
EK:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
long long road[210][210],pre[210];
int n,m;
long long d[200010],h,t;
long long flow[210],ans;
int bfs(int f,int l)
{
h=t=0;
memset(d,0,sizeof(d));
int i,j;
for (i=1;i<=m;i++)
pre[i]=-1;
d[++t]=f; pre[f]=0; flow[f]=0x7ffffff;
while (h!=t)
{
int u;
h=(h%20010)+1;
u=d[h];
if (u==l) break;
for (i=1;i<=m;i++)
if (i!=f&&road[u][i]>0&&pre[i]==-1)
{
pre[i]=u;
flow[i]=min(road[u][i],flow[u]);
t=(t%20010)+1;
d[t]=i;
}
}
if (pre[l]==-1)
return -1;
else return flow[l];
}
long long find(int start,int end)
{
long long sum,s;
sum=s=0;
while ((s=bfs(start,end))!=-1)
{
int k,last;
k=end;
while (k!=start)
{
last=pre[k];
road[last][k]-=s;
road[k][last]+=s;
k=last;
}
sum+=s;
}
return sum;
}
int main()
{
int i,j;
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if (a==b) continue;
road[a][b]+=c;
}
ans=find(1,m);
printf("%lld",ans);
return 0;
}
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long tot,a[420],p[210],next[420],remain[420];
int cur[210],dis[210];
int d[20010],h,t;
int n,m;
long long ans,sum;
void add(int x,int y,int z)
{
tot++; next[tot]=p[x]; a[tot]=y; p[x]=tot; remain[tot]=z;
tot++; next[tot]=p[y]; a[tot]=x; p[y]=tot; remain[tot]=0;
return;
}
bool bfs()
{
int i;
memset(dis,-1,sizeof(dis));
h=0; t=1; d[1]=1; dis[1]=0;
for (i=1;i<=m;++i)
cur[i]=p[i];
while (h!=t)
{
int u,v;
h=(h%20010)+1;
u=d[h];v=p[u];
while (v>=0)
{
if (remain[v]&&dis[a[v]]<0)
{
dis[a[v]]=dis[u]+1;
t=(t%20010)+1;
d[t]=a[v];
}
v=next[v];
}
}
if (dis[m]<0)
return 0;
else return 1;
}
long long dfs(int now,int t,long long low)
{
if (!low||now==t) return low;
int u=cur[now],s1=0,s;
while (u>=0)
{
cur[now]=u;
if (dis[a[u]]==dis[now]+1&&(s=dfs(a[u],t,min(low,remain[u]))))
{
s1+=s; low-=s;
remain[u]-=s; remain[u^1]+=s;
if (!low) break;
}
u=next[u];
}
return s1;
}
int main()
{
int i,j;
memset(next,-1,sizeof(next));
memset(p,-1,sizeof(p));
scanf("%d%d",&n,&m);
for (i=1;i<=n;++i)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
while (bfs())
while (sum=dfs(1,m,0x7fffffff))
ans+=sum;
printf("%lld",ans);
return 0;
}
ISAP:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[420],next[420],p[210],remain[420],tot;
int cur[210],dis[210],last[210],num[210];
int d[20010],h,t;
int n,m;
long long ans;
bool b[210];
inline void add(int x,int y,int s)
{
tot++; next[tot]=p[x]; a[tot]=y; p[x]=tot; remain[tot]=s;
tot++; next[tot]=p[y]; a[tot]=x; p[y]=tot; remain[tot]=0;
return;
}
inline int addflow(int s,int t)
{
int s1=0x7fffffff,now=t;
while (now!=s)
{
s1=min(s1,remain[last[now]]);
now=a[last[now]^1];
}
now=t;
while (now!=s)
{
remain[last[now]^1]+=s1;
remain[last[now]]-=s1;
now=a[last[now]^1];
}
return s1;
}
inline void bfs(int l)
{
int i;
for (i=1;i<=m;++i)
dis[i]=m;
memset(b,false,sizeof(b));
h=0; t=1; d[t]=l; dis[l]=0; b[l]=true;
while (h!=t)
{
int u,v;
h=(h%20010)+1;
u=d[h];
v=p[u];
while (v>=0)
{
if (!b[a[v]]&&remain[v^1])
{
b[a[v]]=true;
dis[a[v]]=dis[u]+1;
t=(t%20010)+1; d[t]=a[v];
}
v=next[v];
}
}
return;
}
inline long long isap(int s,int t)
{
int sum=0,now=s,i;
bfs(t);
for (i=1;i<=m;++i) num[dis[i]]++;//当前这种路径长度出现了几次
for (i=1;i<=m;++i) cur[i]=p[i];//当前弧
while (dis[s]<m)
{
if (now==t)//当前点为终点的增广
{
sum+=addflow(s,t);
now=s;
}
bool h=false;
int u=cur[now];//从上一次搜索到的弧继续搜索
while (u>=0)
{
if (dis[a[u]]+1==dis[now]&&remain[u])//有满足条件的出边
{
h=true;
cur[now]=u;
last[a[u]]=u;
now=a[u];
break;
}
u=next[u];
}
if (h==false)//没有满足条件的出边,重新编号(将层数小的重新编号)
{
int minn=n-1,u;
u=p[now];
while (u>=0)
{
if (remain[u])
minn=min(minn,dis[a[u]]);
u=next[u];
}
--num[dis[now]];
if (!num[dis[now]]) break;//如果重新编号后当前层没边了,则图不连通,不存在增广路了
dis[now]=minn+1;//重新编号
num[minn+1]++;
cur[now]=p[now];
if (now!=s) now=a[last[now]^1];
}
}
return sum;
}
int main()
{
int i;
memset(p,-1,sizeof(p));
memset(next,-1,sizeof(next));
tot=-1;
scanf("%d%d",&n,&m);
for (i=1;i<=n;++i)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
ans=isap(1,m);
printf("%lld",ans);
return 0;
}
既然无能更改,又何必枉自寻烦忧