【codevs 1993】草地排水(最大流)

45 篇文章 0 订阅
31 篇文章 0 订阅
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;
}


Dinic(循环队列+当前弧优化):

#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;
 } 






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值