【USACO4.2.1】草地排水 网络流 最大流

题目描述

  在农夫约翰的农场上,每逢下雨,贝茜最喜欢的三叶草地就积聚了一潭水。这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间。因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没的烦恼(不用担心,雨水会流向附近的一条小溪)。作为一名一流的技师,农夫约翰已经在每条排水沟的一端安上了控制器,这样他可以控制流入排水沟的水流量。
  农夫约翰知道每一条排水沟每分钟可以流过的水量,和排水系统的准确布局(起点为水潭而终点为小溪的一张网)。需要注意的是,有些时候从一处到另一处不只有一条排水沟。
  根据这些信息,计算从水潭排水到小溪的最大流量。对于给出的每条排水沟,雨水只能沿着一个方向流动,注意可能会出现雨水环形流动的情形。

题目大意

有向图最大流

数据范围

N,M≤200

样例输入

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

样例输出

50

解题思路

  • 算法思想:利用距离标号,寻找允许路来得到最短增广路。在找不到允许弧时让距离标号增加。
  • 算法步骤:
      (1)dis(s)=0,因为离自已的距离为0。
      (2)对残量网络N(x)的任意一条弧(i,j),dis(i)<=dis(j)+1,即距离标号不能太大。
      (3)如果残量网络N(x)中的弧满足dis(i)=dis(j)+1(且map[i][j] > 0),我们称(i,j)是允许弧。只由允许弧组成的路是允许路。显然,允许路是残量网络N(x)中的最短增广路,但是最短增广路并不一定对应一条允许路,因此有时候需要修改距离标号dis[i] = min{ dis[j] + 1 | map[i][j] > 0);通过增加一些弧来得到允许路。如此容易知道当dis[s] = n时就增广完毕,因为从源点到汇点最多有n-1步。最初dis数组可以用一个BFS初始化,但是实践中dis全部初始为0。

代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
inline int Getint(){int x=0,f=1;char ch=getchar();while('0'>ch||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
int n,m,cnt=0,h[205],dis[205],gap[205];
struct node{int to,next,v,pair;}e[405];
void AddEdge2(int x,int y,int v,int pa){e[cnt].to=y;e[cnt].next=h[x];e[cnt].v=v;e[cnt].pair=pa;h[x]=cnt;}//用邻接表的小优化
void AddEdge(int x,int y,int v){
    AddEdge2(x,y,v,++cnt+1);//正向边
    AddEdge2(y,x,0,++cnt-1);//反向边
}
int SAP(int x,int Maxflow){
    if(x==n)return Maxflow;//如果到了终点则返回Maxflow
    int tmp=Maxflow;
    for(int p=h[x];p;p=e[p].next){
        int y=e[p].to;//枚举可到达的顶点
        int flow=min(e[p].v,tmp);//这条边能流过的量为边与当前剩余流量的最小值
        if(flow&&(dis[x]==dis[y]+1)){//如果有流量并且编号相邻
            int ret=SAP(y,flow);
            tmp-=ret;//剩余流量减去用过的流量
            e[p].v-=ret;//边剩余流量减去流量
            e[e[p].pair].v+=ret;//反向边加上流量(应该是叫后悔操作吧)
            if(dis[1]==n||!tmp)return Maxflow-tmp;//如果起点的标号已经到了N或者当前点已经没有流量了则返回
        }
    }
    if(!(--gap[dis[x]]))dis[1]=n;//断层了,故将dis[1]设为n,直接终止main中的while
    else gap[++dis[x]]++;//当前标号加一,gap标号也加一
    return Maxflow-tmp;
}
int main(){
    memset(dis,0,sizeof(dis));
    int Ans=0;
    m=Getint(),n=Getint();
    for(int i=1;i<=m;i++){
        int x=Getint(),y=Getint(),v=Getint();
        AddEdge(x,y,v);//建边
    }
    gap[0]=n;//初始标号均为0
    while(dis[1]<n)Ans+=SAP(1,1<<30);//SAP求最大流
    cout<<Ans;
    return 0;
}

转载于:https://www.cnblogs.com/Cedric341561/p/6811054.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值