题目链接: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. WCF+Nhibernate循环引用导致序列化的问题

    WCF+Nhibernate 在查询中只要涉及到表关联,都会存在一个循环引用而导致客户端不能反序列化的问题. 解决的办法: 1.多对一关联中,设置lazy="false". 2.一 ...

  2. SpringBoot自动配置xxxAutoConfiguration 的使用

    https://sdqali.in/blog/2016/07/16/controlling-redis-auto-configuration-for-spring-boot-session/ 常用的类 ...

  3. Java从控制台接受输入字符

    创建一个类,在该类的主方法中创建Scanner扫描起来封装System类的in输入流,然后提示用户输入身份证号码,并输入身份证号码的位数. 代码如下: import java.util.Scanner ...

  4. eclipse debug Liunx服务器上的svn项目

    1.本地项目提交到svn上,以保证本地代码与服务器代码相同 2.开启服务器debug端口 3.使用root账号重新部署服务器项目并监听catalina.out sh /home/p/deploy/gt ...

  5. windows Redis绑定ip无效,Redis设置密码无效,Windows Redis 配置不生效, Windows Redis requirepass不生效

    windows Redis绑定ip无效,Redis设置密码无效,Windows Redis 配置不生效, Windows Redis requirepass不生效 >>>>&g ...

  6. PostgreSQL的表空间

    1. 表空间的概念 PostgreSQL中的表空间允许在文件系统中定义用来存放表示数据库对象的文件的位置.在PostgreSQL中表空间实际上就是给表指定一个存储目录. 2. 表空间的作用 官方解释 ...

  7. 【代码审计】iZhanCMS_v2.1 代码执行漏洞分析

      0x00 环境准备 iZhanCMS官网:http://www.izhancms.com 网站源码版本:爱站CMS(zend6.0) V2.1 程序源码下载:http://www.izhancms ...

  8. java.lang.IllegalArgumentException: No converter found for return value of type

    原文地址: http://blog.csdn.net/linhaiguo/article/details/51554766 问题原因: 请求返回的数据无法转换,需要添加如下配置 解决方法: 1.在po ...

  9. java.security.NoSuchAlgorithmException: SHA1PRNG SecureRandom not available

    好久没有使用MyEclipse10了,今天打开看了以前大学的项目,在Tomcat7中发布启动,我嚓嘞,报错: SEVERE: Exception initializing random number ...

  10. 关于CreateProcess函数一些经验

    TCHAR szCmdLine[]={TEXT("E:\\CPL-server\\其他工具\\restartSrv\\bin\\opensavepath.exe")}; TCHAR ...