题目链接: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. Java实现快速批量移动文件

    文件移动是计算机资源管理常用的一个操作,这在操作系统中可以通过文件的剪切与复制或鼠标拖动来实现.但是在Java文件的编程实现中,大多是通过复制文件到目的地,再删除所有文件来实现的.这对于小文件来说看不 ...

  2. hdu5289 2015多校联合第一场1002 Assignment

    题意:给出一个数列.问当中存在多少连续子区间,当中子区间的(最大值-最小值)<k 思路:设dp[i]为从区间1到i满足题意条件的解.终于解即为dp[n]. 此外 如果对于arr[i] 往左遍历 ...

  3. mongodb 关闭服务器

    ./mongo use admin db.shutdownServer() 啦啦啦

  4. pip更换下载源(提升下载速度)

    经常在使用Python的时候需要安装各种模块,而pip是很强大的模块安装工具,但是由于国外官方pypi经常被墙,导致不可用,或者下载速度很慢,所以我们最好是将自己使用的pip源更换一下,这样就能解决被 ...

  5. java中的编码和编码格式问题

    看来问的人和回答的人都不一定清楚什么是“编码和编码格式”,以及如何理解“java中字符串的编码”;首先明确几点: unicode是一种“编码”,所谓编码就是一个编号(数字)到字符的一种映射关系,就仅仅 ...

  6. bing搜索引擎子域名收集(Python脚本)

    利用bing搜索引擎进行子域名收集,编写了一个简单的Python脚本,分享一下. #! /usr/bin/env python # _*_ coding:utf-8 _*_ import reques ...

  7. jQuery ajax中serialize()方法增加其他参数

    表单提交 使用jQuery.ajax()进行表单提交时,需要传递参数,最直接的方法便是使用Form的serializa()将表单序列化,前提只是将Form表单中的name属性与数据库的字段名保持一致便 ...

  8. 【LeetCode OJ】Swap Nodes in Pairs

    题目:Given a linked list, swap every two adjacent nodes and return its head. For example,Given 1->2 ...

  9. VC++中如何复制对话框资源

    法1:   在你的工程中添加另一个工程的rc文件,这时资源视图中就会出现两个rc,从后加的rc中拷贝资源到你自己工程的rc中就可以了.       法2:vc中如何拷贝一个工程的对话框资源到另一个工程 ...

  10. Webpack 备忘录

    Webpack 属于在项目中配置一次就很少改动的那种工具,但这样就导致新项目再配置 Webpack 时会有些生疏,所以将 Webpack 核心概念及常用配置记录如下. 1)核心概念 Webpack 4 ...