草地排水 洛谷P2740 最大流 入门题目
草地排水 洛谷P2740 最大流入门题目
题意
在农夫约翰的农场上,每逢下雨,贝茜最喜欢的三叶草地就积聚了一潭水。这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间。因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没的烦恼(不用担心,雨水会流向附近的一条小溪)。作为一名一流的技师,农夫约翰已经在每条排水沟的一端安上了控制器,这样他可以控制流入排水沟的水流量。
农夫约翰知道每一条排水沟每分钟可以流过的水量,和排水系统的准确布局(起点为水潭而终点为小溪的一张网)。需要注意的是,有些时候从一处到另一处不只有一条排水沟。
根据这些信息,计算从水潭排水到小溪的最大流量。对于给出的每条排水沟,雨水只能沿着一个方向流动,注意可能会出现雨水环形流动的情形。
输入格式
第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)是这条排水沟的最大容量。
输出格式
输出一个整数,即排水的最大流量。
//下面是样例输入
5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10
//样例输出
50
解题思路
这个是我学习最大流算法时,看到有博客说这个是个入门题目,确实很基础。
具体的最大流讲解就不说了,推荐看这个博客网络流入门之最大流算法(增广路算法 由Ford-Fulkerson到Edmonds-Karp到dinic) 包看懂,确实讲的不错,尤其是他的代码实现是那种最基本的形式。
下面的代码两个版本,一个是基于他的进行了更改,另一个是看的《算法竞赛入门经典(第二版)》368页的实现代码,更加的高级吧。
代码实现
//我的EK写法。。。建议邻接矩阵
//题目:洛谷p2740 草地排水
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
int m,n,cap[205][205],pre[205],flow[205][205];
int vis[205];
bool bfs(int s,int t)
{
//    memset(pre,-1,sizeof(pre));
    memset(vis,0,sizeof(vis));
    queue<int> q;
    q.push(s);
    vis[s]=inf;
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        for(int i=1;i<=n;i++)
        {
            //这里vis不仅代表标记,还记录了到这个结点可以减去的最小流量值
            //这样就省去了max_flow中的第一个for循环
            if(vis[i]==0 && i!=now && cap[now][i]-flow[now][i]>0)
            {
                q.push(i);
                pre[i]=now;
                vis[i]=min(vis[now], cap[now][i]-flow[now][i]);
                if(i==t)	return true;	//找到了
            }
        }
    }
    return false;
}
int max_flow(int s,int t)
{
    int ans=0;
    while(bfs(s,t))
    {
        //这个for循环的作用就是找到一条到达重点的路中,最小的剩余流量值
//      int delta=0x7fffffff;
//      for(int i=t;i!=s;i=pre[i])
//      {
//          delta=min(delta,cap[pre[i]][i]-flow[pre[i]][i]);
//      }
        for(int i=t;i!=s;i=pre[i])
        {
//          flow[pre[i]][i]+=delta;
//          flow[i][pre[i]]-=delta;
			flow[pre[i]][i]+=vis[t];
			flow[i][pre[i]]-=vis[t];
        }
        ans+=vis[t];	//这是一个结论 记住就行
    }
    return ans;
}
int main()
{
    cin>>m>>n;
    for(int i=1;i<=m;i++)
    {
        int x,y,rl;
        cin>>x>>y>>rl;
        //必须是+= 超级阴人.....没有看到一处到另一处不止一条排水沟
        cap[x][y]+=rl;
        cap[y][x]+=rl;
        flow[x][y]=0;
      	flow[y][x]+=rl;
    }
    cout<<max_flow(1,n);
    return 0;
}
//下面的代码是自己对《算法竞赛入门经典》中关于最大流的写法
//因为这个题中,两个点之间不仅只有一条路,所以开始使用邻接矩阵,然后再使用加边函数来进行操作
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=300;
struct Edge{
	int from, to, cap, flow;
	Edge(int u, int v, int c, int f):from(u), to(v), cap(c), flow(f){}
};
vector<Edge> edges;
vector<int> G[maxn];//邻接表,G[i][j],表示结点i的第j条边在edges[j]中。
int vis[maxn], pre[maxn], cap[205][205];//pre用来记录路径
int n, m;
void init()
{
	for(int i=0; i<=n; i++)	G[i].clear();
	edges.clear();
}
inline void addedge(int from, int to, int cap) //这里使用了inline函数,一定条件下可以减少运行时间
{
	edges.push_back(Edge(from, to, cap, 0));
	edges.push_back(Edge(to, from, cap, cap));
	int m=edges.size();
	G[from].push_back(m-2);
	G[to].push_back(m-1);
}
bool bfs(int s, int t)
{
	memset(vis, 0,sizeof(vis));
	queue<int> Q;
	Q.push(s);
	vis[s]=inf;
	while(!Q.empty())
	{
		int x=Q.front(); Q.pop();
		for(int i=0; i<G[x].size(); i++)
		{
			Edge &e=edges[G[x][i]];
			if(!vis[e.to] && e.cap > e.flow)
			{
				pre[e.to]=G[x][i];
				vis[e.to]=min(vis[x], e.cap-e.flow);
				Q.push(e.to);
			}
		}
		if(vis[t])	return true;
	}
	return false;
}
int maxflow(int s, int t)
{
	int flow = 0;
	while(bfs(s, t))
	{
		for(int u=t; u!=s; u=edges[pre[u]].from)
		{
			edges[pre[u]].flow += vis[t];
			edges[pre[u]^1].flow -= vis[t];
		}
		flow += vis[t];
	}
	return flow;
}
int main()
{
	int x, y, rl;
	scanf("%d%d", &m, &n);
	memset(cap, 0, sizeof(cap));
	for(int i=1; i<=m; i++)
	{
		scanf("%d%d%d", &x, &y, &rl);
		cap[x][y]+=rl;
	}
	for(int i=1; i<=n; i++)
	{
		for(int j=1; j<=n; j++)
		{
			if(cap[i][j]!=0)
				addedge(i, j, cap[i][j]);
		}
	}
	printf("%d\n", maxflow(1, n));
	return 0;
 }
草地排水 洛谷P2740 最大流 入门题目的更多相关文章
- bzoj 5120 无限之环 & 洛谷 P4003 —— 费用流(多路增广SPFA)
		题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5120 https://www.luogu.org/problemnew/show/P4003 ... 
- 洛谷P2740 [USACO4.2]草地排水Drainage Ditches
		题目背景 在农夫约翰的农场上,每逢下雨,贝茜最喜欢的三叶草地就积聚了一潭水.这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间.因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没 ... 
- 洛谷P2740 草地排水
		最大流 一道完全符合最大流定义的板子题..重新学了一次网络流,希望有更深的理解把.. #include <bits/stdc++.h> #define INF 0x3f3f3f3f #de ... 
- 【USACO4.2】草地排水Drainage Ditches(最大流)
		题目背景 在农夫约翰的农场上,每逢下雨,贝茜最喜欢的三叶草地就积聚了一潭水.这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间.因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没 ... 
- 洛谷P2604 最大流+最小费用最大流
		题目链接:https://www.luogu.org/problem/P2604 题目描述 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1. 在 ... 
- 【学术篇】树上差分--洛谷3128最大流Max Flow
		懒得贴题目,直接放不稳定的传送门(雾):点击前往暴风城(雾) 据说这题是BZOJ3490,但本蒟蒻没有权限╮(╯_╰)╭ 这题似乎就是裸树上差分... 对于树上(x,y)之间的路径上的点区间c[i]加 ... 
- 【洛谷T7152】(考试题目)细胞
		题面 题目描述 小 X 在上完生物课后对细胞的分裂产生了浓厚的兴趣.于是他决定做实验并 观察细胞分裂的规律. 他选取了一种特别的细胞,每天每个该细胞可以分裂出 x − 1 个新的细胞. 小 X 决定第 ... 
- 【洛谷2469/BZOJ1927】[SDOI2010]星际竞速(费用流/最小路径覆盖)
		题目: 洛谷2469 分析: 把题目翻译成人话:给一个带边权的DAG,求一个路径覆盖方案使路径边权总和最小.从点\(i\)开始的路径需要额外加上\(A_i\)的权值. 回xian忆chang一xue下 ... 
- DP【洛谷P2363】马农
		[洛谷P2363]马农 题目描述 在观看完战马检阅之后,来自大草原的两兄弟决心成为超级"马农",专门饲养战马. 兄弟两回到草原,将可以养马的区域,分为N*N的单位面积的正方形,并实 ... 
随机推荐
- TensorFlow使用记录 (十四): Multi-task to MNIST + Fashion MNIST
			前言 后面工作中有个较重要的 task 是将 YOLOV3 目标检测和 LanNet 车道线检测和到一个网络中训练,特别的是,这两部分数据来自于不同的数据源.这和我之前在 caffe 环境下训练检测整 ... 
- 删除git的远程分支
			命令:$ git push origin [空格][冒号][需要删除的分支名字] git push origin :dev 删除git的凭证的方法: 控制面板\用户帐户\凭据管理器 --->普 ... 
- Tree-based Model 如何处理categorical variable
			categorical variable 分为 order variale 和 non-order variable,其中order variable直接使用sklearn.preprocess.La ... 
- Linux  变量 $$ $! $?  $-  $#   $*  $@  $0   $n
			[参考文章]:linux中shell变量$#,$@,$0,$1,$2的含义解释 1. 变量说明 1.1 $$ Shell本身的PID(ProcessID) 1.2 $! Shell最后运行的后台Pro ... 
- maven 安装后变成 mvn 不是内部命令解决方法
			1.maven的安装教程 下载地址为:http://maven.apache.org/download.cgi 进入此页面之后 点击下载,然后解压,我把目录名改为maven,目录结构如下图所示 下面我 ... 
- selenium 入门(Java)
			官网:https://www.seleniumhq.org/ 下载地址:https://sites.google.com/a/chromium.org/chromedriver/downloads 华 ... 
- nvl(sum(字段),0) 的时候,能展示数据0,但是group by 下某个伪列的时候,查不到数据(转载)
			今天碰到一个比较有疑惑的问题,就是在统计和的时候,我们往往有时候查不到数据,都会再加个 nvl(sum(字段),0) 来显示这个字段,但是如果我们再加个group by ,就算有加入这个 nvl(nu ... 
- 前端之路(一)之W3C是什么?
			W3C 指万维网联盟(World Wide Web Consortium) W3C 最重要的工作是发展 Web 规范(称为推荐,Recommendations),这些规范描述了 Web 的通信协议(比 ... 
- Jenkins笔录
			1.Linux下安装jdk8的方法 ,只需要一条命令就可以安装jdk: yum install java-1.8.0-openjdk* -y 执行过这条命令无需配置,直接可以使用. 2.JDK12版本 ... 
- [转] Maven 从命令行获取项目的版本号
			[From]https://blog.soebes.de/blog/2018/06/09/help-plugin/ I bet you have been faced with the situati ... 
