【USACO4.2】草地排水Drainage Ditches(最大流)

题目背景

在农夫约翰的农场上,每逢下雨,贝茜最喜欢的三叶草地就积聚了一潭水。这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间。因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没的烦恼(不用担心,雨水会流向附近的一条小溪)。作为一名一流的技师,农夫约翰已经在每条排水沟的一端安上了控制器,这样他可以控制流入排水沟的水流量。

题目描述

农夫约翰知道每一条排水沟每分钟可以流过的水量,和排水系统的准确布局(起点为水潭而终点为小溪的一张网)。需要注意的是,有些时候从一处到另一处不只有一条排水沟。

根据这些信息,计算从水潭排水到小溪的最大流量。对于给出的每条排水沟,雨水只能沿着一个方向流动,注意可能会出现雨水环形流动的情形。

输入格式:

第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)是这条排水沟的最大容量。

输出格式:

输出一个整数,即排水的最大流量

输入样例#1:

5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10

输出样例#1:

50

题解

网络流最大流的模板题
直接使用EK/Dinic/FF(这个不保证能够过)即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
#define MAX 10100
#define MAXL 210000
#define rg register 
#define INF 1000000000
inline int read()
{
       rg int x=0,t=1;rg char ch=getchar();
       while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
       if(ch=='-'){t=-1;ch=getchar();}
       while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
       return x*t;
}
int N,M,S,T,Ans=0;
int a[MAX];
queue<int> Q; 
int pre[MAXL];
struct Line
{
       int u,v,next,w,c,fb;//w是流量,c是容量  
}e[MAXL];
int h[MAX],cnt=1;
inline void Add(rg int u,rg int v,rg int w)
{
        e[cnt]=(Line){u,v,h[u],0,w,cnt+1};
        h[u]=cnt++;
        e[cnt]=(Line){v,u,h[v],0,0,cnt-1};//存反边 
        h[v]=cnt++;
}
int main()
{
        M=read();N=read();S=1;T=N;
        for(rg int i=1;i<=M;++i)
        {
               rg int u=read(),v=read(),w=read();
               Add(u,v,w);
        }
        rg int Ans=0;
        while(1)//不断寻找增广路径 
        {
               for(rg int i=1;i<=N;++i)a[i]=0;
               while(!Q.empty())Q.pop();
               Q.push(S);
               pre[S]=0;
               a[S]=INF;
               while(!Q.empty())
               {
                     int u=Q.front();Q.pop();
                     for(int i=h[u];i;i=e[i].next)
                     {
                           int v=e[i].v;
                           if(!a[v]&&e[i].c>e[i].w)//可以增广 
                           {
                                a[v]=min(a[u],e[i].c-e[i].w);//求最小的流量
                                pre[v]=i;//储存增广路径 
                                Q.push(v); 
                           }
                     }
                     if(a[T])break;//增广到了终点 
               }
               if(!a[T])break;//未增广 
               for(int u=T;u!=S;u=e[pre[u]].u)//增加流量 
               {
                      e[pre[u]].w+=a[T];
                      e[e[pre[u]].fb].w-=a[T];
               }
               Ans+=a[T];
        }
        printf("%d\n",Ans);
        return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值