题目链接: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. [AX]AX2012 R2 出差申请和支出报告

    AX2012中有个模块叫做出差和支出,用于管理出差以及相关的费用,用户只能在员工自助服务EP站点上提交出差申请.费用报销报告,在Client程序中做审核以及后续的支付动作等,最后形成相关的财务分录. ...

  2. JSONP 劫持漏洞实例

    0x01 Jsonp简介 Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据. 为什么我们从 ...

  3. metasploit 中的DB

    渗透测试任务中,主机/服务/漏洞等信息如果手动维护,会带来巨大的工作量. 在metasploit中,这部分工作已经被封装的非常好,每次调用内部模块执行的任务结果都会自动存入DB.通过简单的指令即可以方 ...

  4. Nginx 代理

    如下,配置 Nginx 成为一台代理服务器 [root@localhost ~]$ cat /usr/local/nginx/conf/vhost/proxy.conf server { listen ...

  5. JDBC批量加密数据库密码

    package com.lxc.wmb; import java.io.UnsupportedEncodingException; import java.security.MessageDigest ...

  6. iOS - UIScrollView 相关属性代理详解

    一.UIScrollView的属性和代理方法详解 属性: - (void)viewDidLoad { [super viewDidLoad]; _scrollView.backgroundColor ...

  7. <转>python字典排序 关于sort()、reversed()、sorted()

    一.Python的排序 1.reversed() 这个很好理解,reversed英文意思就是:adj. 颠倒的:相反的:(判决等)撤销的 print list(reversed(['dream','a ...

  8. 【推荐系统论文笔记】Introduction To Recommender Systems: Algorithms and Evaluation

    这篇论文比较短,正如题目所说,主要还是简单地介绍了一下推荐系统的一些算法以及评估的方法. 推荐系统之前是基于关键字信息的过滤系统,后来发展成为协同过滤系统,解决了两个问题:1.通过人工审核去评价那些具 ...

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

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

  10. QSS样式表之PS黑色风格+白色风格+淡蓝色风格(开源)

    用QUI皮肤生成器制作皮肤,基本上不超过一分钟就可以生成一套自己想要的皮肤,只要设置八种颜色即可.本人非常喜欢这套黑色风格样式皮肤,特意分享出来,下载地址:https://download.csdn. ...