题目链接:http://poj.org/problem?id=1273

Time Limit: 1000MS Memory Limit: 10000K

Description

Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage ditches so that Bessie's clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into that ditch. 
Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network. 
Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle. 
 

Input

The input includes several cases. For each case, the first line contains two space-separated integers, N (0 <= N <= 200) and M (2 <= M <= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections points for those ditches. Intersection 1 is the pond. Intersection point M is the stream. Each of the following N lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei <= M) designate the intersections between which this ditch flows. Water will flow through this ditch from Si to Ei. Ci (0 <= Ci <= 10,000,000) is the maximum rate at which water will flow through the ditch.

Output

For each case, output a single integer, the maximum rate at which water may emptied from the pond.
 

Sample Input

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

Sample Output

50

Source

USACO 93
 
题意:给出 $n$ 条边,$m$ 个点,编号 $1$ ~ $m$,$1$ 是源点,$m$ 是汇点,求最大流。
 
题解: 
属于模板题,直接用刘汝佳第二版上的模板就可以过。
该模板,使用邻接表存图,vector E用来存所有的边,G[i]用来存所有以i为起点的边的编号;
 
存入每条边的同时也存入一条反向边,这样就可以存储网络本身,同时存储对应的残存网络:
  每条边初始情况有:u,v,c,f四个值,代表这条边的{from,to,cap,flow};
  网络中真实存在的边,初始存入from,to,flow=0,cap,而它对应的残存边不难得知为:{from,to,/,cap-flow},
  而其对应的反向边,则也是残存网络的另一部分,在理论上,其容量也应为正值,应表示为{from,to,/,flow},
  我们在理论的讨论中,对于残存边和反向边统一看待,但当我们实际运用在代码中时,我们对于每条边的残存余量都表示为cap-flow(edge.c-edge.f),
  那么,我们就要对反向边做一定修改,将其改为{from,to,-flow,0},这样,就可以统一使用cap-flow来表示残存余量。
 
然后,是算法主体部分,Edmonds-Karp算法使用BFS寻找增广路径,用aug[]数组存储源点到当前节点的残存容量(可增广量),这样随着搜索深度加深,最后到达汇点t时aug[t]就是这条增广路径的残存容量;
 
那么,既然要对这条路径上的所有边都进行增广,我们怎么样才能重现用BFS找到的这条增广路径呢?
模板使用了pre[]数组,用以记录这条路径上的每个点的入弧的编号,也就是说,知道了一个节点to,我们就通过pre[to]知道了edge在vector E中的编号,进而通过访问E得到edge,进而得到edge的from,依次往前逆推路径;
 
 #include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#define MAX 203
#define INF 0x3f3f3f3f
using namespace std;
int n,m;//n条边,m个点
struct Edge{
int u,v,c,f;
};
struct EdmondsKarp{
vector<Edge> E;
vector<int> G[MAX];
int aug[MAX];//源点到i的可增广量
int pre[MAX];//记录当前路径中点i的入弧编号
void init(int n)
{
E.clear();
for(int i=;i<n;i++) G[i].clear();
}
void addedge(int from,int to,int cap)
{
E.push_back((Edge){from,to,cap,});
E.push_back((Edge){to,from,,});
G[from].push_back(E.size()-);
G[to].push_back(E.size()-);
}
int maxflow(int s,int t)
{
int flow=;
while()
{
memset(aug,,sizeof(aug));
queue<int> q;
q.push(s);
aug[s]=INF;
while(!q.empty())
{
int now=q.front(); q.pop();
for(int i=;i<G[now].size();i++)
{
Edge edge=E[G[now][i]];
if(!aug[edge.v] && edge.c>edge.f)
{
pre[edge.v]=G[now][i];
aug[edge.v]=min(aug[now],edge.c-edge.f);
q.push(edge.v);
}
}
if(aug[t]) break;
}
if(!aug[t]) break;
for(int i=t;i!=s;i=E[(pre[i])].u)
{
E[pre[i]].f+=aug[t];
E[pre[i]^].f-=aug[t];
}
flow+=aug[t];
}
return flow;
}
}EK;
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
EK.init(m);
for(int from,to,cap,i=;i<=n;i++)
{
scanf("%d%d%d",&from,&to,&cap);
EK.addedge(from,to,cap);
}
printf("%d\n",EK.maxflow(,m));
}
}

注:

  ①代码第51行:“if(aug[t]) break;”语句,由于我们一次BFS只找到一条增广路径,所以aug[]数组每次BFS之前都进行初始化为零,因此一旦aug[t]不为零,那么必然我们已经找到了一条增广路径,这是就没必要继续进行BFS,直接跳出循环,节省时间。

  ②代码第53行:“if(!aug[t]) break;”语句,这是在BFS循环外的判断语句,因为若是当我们进行完一遍BFS,未找到一条增广路径,那么根据最大流最小割定理,当前已经是最大流情况,所以立即跳出即可。

最大流最小割定理:

嗯,然后再补一个Dinic算法版的:

 #include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#define MAX 203
#define INF 0x3f3f3f3f
using namespace std;
int n,m;//n条边,m个点
struct Dinic
{
struct Edge{
int u,v,c,f;
};
int s,t;
vector<Edge> E;
vector<int> G[MAX];
bool vis[MAX]; //BFS使用
int lev[MAX];//记录层次
int cur[MAX]; //当前弧下标
void init(int n)
{
E.clear();
for(int i=;i<n;i++) G[i].clear();
}
void addedge(int from,int to,int cap)
{
E.push_back((Edge){from,to,cap,});
E.push_back((Edge){to,from,,});
G[from].push_back(E.size()-);
G[to].push_back(E.size()-);
}
bool bfs()
{
memset(vis,,sizeof(vis));
queue<int> q;
q.push(s);
lev[s]=;
vis[s]=;
while(!q.empty())
{
int now=q.front(); q.pop();
for(int i=,_size=G[now].size();i<_size;i++)
{
Edge edge=E[G[now][i]];
int nex=edge.v;
if(!vis[nex] && edge.c>edge.f)//属于残存网络的边
{
lev[nex]=lev[now]+;
q.push(nex);
vis[nex]=;
}
}
}
return vis[t];
}
int dfs(int now,int aug)//now表示当前结点,aug表示目前为止的最小残量
{
if(now==t || aug==) return aug;//aug等于0时及时退出,此时相当于断路了
int flow=,f;
for(int& i=cur[now],_size=G[now].size();i<_size;i++)//从上次考虑的弧开始,注意要使用引用,同时修改cur[now]
{
Edge& edge=E[G[now][i]];
int nex=edge.v;
if(lev[now]+ == lev[nex] && (f=dfs(nex,min(aug,edge.c-edge.f)))>)
{
edge.f+=f;
E[G[now][i]^].f-=f;
flow+=f;
aug-=f;
if(!aug) break;//aug等于0及时退出,当aug!=0,说明当前节点还存在另一个增广路分支
}
}
return flow;
}
int maxflow(int s,int t)//主过程
{
int flow=;
while(bfs())//不停地用bfs构造分层网络,然后用dfs沿着阻塞流增广
{
memset(cur,,sizeof(cur));
flow+=dfs(s,INF);
}
return flow;
}
}dinic;
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
dinic.init(m);
for(int from,to,cap,i=;i<=n;i++)
{
scanf("%d%d%d",&from,&to,&cap);
dinic.addedge(from,to,cap);
}
dinic.s=, dinic.t=m;
printf("%d\n",dinic.maxflow(,m));
}
}

具体Dinic算法是个什么操作可以参见:王欣上《浅谈基于分层思想的网络流算法》.pdf

模板:

 #include<cstring>
#include<vector>
#include<queue>
#define MAX 100
#define INF 0x3f3f3f3f
struct Edge{
int u,v,c,f;
};
struct Dinic
{
int s,t;
vector<Edge> E;
vector<int> G[MAX];
bool vis[MAX];
int lev[MAX];
int cur[MAX];
void init(int l,int r)
{
E.clear();
for(int i=l;i<=r;i++) G[i].clear();
}
void addedge(int from,int to,int cap)
{
E.push_back((Edge){from,to,cap,});
E.push_back((Edge){to,from,,});
int m=E.size();
G[from].push_back(m-);
G[to].push_back(m-);
}
bool bfs()
{
memset(vis,,sizeof(vis));
queue<int> q;
q.push(s);
lev[s]=;
vis[s]=;
while(!q.empty())
{
int now=q.front(); q.pop();
for(int i=,_size=G[now].size();i<_size;i++)
{
Edge edge=E[G[now][i]];
int nex=edge.v;
if(!vis[nex] && edge.c>edge.f)
{
lev[nex]=lev[now]+;
q.push(nex);
vis[nex]=;
}
}
}
return vis[t];
}
int dfs(int now,int aug)
{
if(now==t || aug==) return aug;
int flow=,f;
for(int& i=cur[now],_size=G[now].size();i<_size;i++)
{
Edge& edge=E[G[now][i]];
int nex=edge.v;
if(lev[now]+ == lev[nex] && (f=dfs(nex,min(aug,edge.c-edge.f)))>)
{
edge.f+=f;
E[G[now][i]^].f-=f;
flow+=f;
aug-=f;
if(!aug) break;
}
}
return flow;
}
int maxflow()
{
int flow=;
while(bfs())
{
memset(cur,,sizeof(cur));
flow+=dfs(s,INF);
}
return flow;
}
}dinic;

POJ 1273 - Drainage Ditches - [最大流模板题] - [EK算法模板][Dinic算法模板 - 邻接表型]的更多相关文章

  1. poj 1273 Drainage Ditches 最大流入门题

    题目链接:http://poj.org/problem?id=1273 Every time it rains on Farmer John's fields, a pond forms over B ...

  2. Poj 1273 Drainage Ditches(最大流 Edmonds-Karp )

    题目链接:poj1273 Drainage Ditches 呜呜,今天自学网络流,看了EK算法,学的晕晕的,留个简单模板题来作纪念... #include<cstdio> #include ...

  3. POJ 1273 Drainage Ditches | 最大流模板

    #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #defi ...

  4. POJ 1273 Drainage Ditches(最大流Dinic 模板)

    #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n, ...

  5. POJ 1273 Drainage Ditches 最大流

    这道题用dinic会超时 用E_K就没问题 注意输入数据有重边.POJ1273 dinic的复杂度为O(N*N*M)E_K的复杂度为O(N*M*M)对于这道题,复杂度是相同的. 然而dinic主要依靠 ...

  6. poj 1273 Drainage Ditches(最大流)

    http://poj.org/problem?id=1273 Drainage Ditches Time Limit: 1000MS   Memory Limit: 10000K Total Subm ...

  7. POJ 1273 Drainage Ditches (网络最大流)

    http://poj.org/problem? id=1273 Drainage Ditches Time Limit: 1000MS   Memory Limit: 10000K Total Sub ...

  8. POJ 1273 Drainage Ditches(网络流dinic算法模板)

    POJ 1273给出M条边,N个点,求源点1到汇点N的最大流量. 本文主要就是附上dinic的模板,供以后参考. #include <iostream> #include <stdi ...

  9. 网络流最经典的入门题 各种网络流算法都能AC。 poj 1273 Drainage Ditches

    Drainage Ditches 题目抽象:给你m条边u,v,c.   n个定点,源点1,汇点n.求最大流.  最好的入门题,各种算法都可以拿来练习 (1):  一般增广路算法  ford() #in ...

随机推荐

  1. Tomcat------如何配置域名和80端口

    1.打开Tomcat的默认安装路径下的Service.xml文件 路径:C:\Program Files\Apache Software Foundation\Tomcat 8.0\conf\Serv ...

  2. SqlServer当前月份时间

    SqlServer当前月份时间 SELECT -DAY(getdate()+-DAY(getdate()))

  3. iOS .tdb代替.dylib

    原文链接:http://www.meniny.cn/2015/09/22/00-00-01-iOS_Xcode_7_tbd/ 不少升级 Xcode 7 的小伙伴们都表示在引入动态库时惊呆了,因为熟悉的 ...

  4. springboot学习过程笔记

    1.spring-boot-devtools热部署在IDEA中配置后不起作用(Eclipse设置了自动编译,所以不用额外设置) 1).pom.xml添加spring-boot-devtools依赖后 ...

  5. springboot测试service层的单元测试

    package com.test.service; import com.task.Application;import com.task.model.po.TaskRecordDo;import o ...

  6. Kubernetes 相关概念

    Node: (1) Node(节点)也就是宿主机,宿主机可以是物理机 .云主机 .虚拟机等等,我们可以在一个宿主机上跑多个容器(container)(2) Node 上会被分配一些工作负载(即 doc ...

  7. 2018.8.23几日重新编译OSG+OE+Qt遇到的问题

    Qt安装多个版本的时候,注意屏蔽掉不使用的Qt,例如OE中的CMakeLists.txt中的# FIND_PACKAGE(Qt4) 使用以前编译好的libcurl.dll现在出现"无法定位序 ...

  8. STL——算法简介

    一.算法概观 以有限的步骤,解决逻辑或数学上的问题,这一专门科目我们称为算法.特定的算法往往搭配特定的数据结构,例如binary search tree(二叉搜索树)和 RB-tree 便是为了解决查 ...

  9. 文件系统的挂载(2)---挂载rootfs文件系统

    一.目的 本文主要讲述linux内核rootfs文件系统的挂载过程,内核版本为3.10. rootfs是基于内存的文件系统,没有实际的存储设备,所有操作都在内存中完成.为了保证linux内核的精简性, ...

  10. springboot---->springboot中的类型转换(一)

    这里面我们简单的学习一下springboot中关于类型转换器的使用.人世间的事情莫过于此,用一个瞬间来喜欢一样东西,然后用多年的时间来慢慢拷问自己为什么会喜欢这样东西. springboot中的类型转 ...