网络流初步
Posted qgmzbry
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络流初步相关的知识,希望对你有一定的参考价值。
今天终于接触了传说中的网络流,果然原地爆炸。
虽然只是掌握了 一点点皮毛,但还是写出来记录一下。
介绍分析:
先介绍一些比较枯燥但是也很简单的定义(自己理解的,虽然并不严谨):
- 源点:只出不进的点
- 汇点:只进不出的点
- 容量和流量:容量相当于电阻的额定电流,而流量相当于实际电流,显然,实际电流是不能大于额定电流的。
- 最大流:相当于源点的最大输入电流
- 我们这里的节点相当于电学里面的节点,即总输入电流显然等于总输出电流,而且节点不能储存电流
- 最大流问题就是在给定线路关系和额定电流后询问最大的输入电流。
那么,如何解决这种问题呢?
如果我们不是准备用固定算法解决问题,而只是用人脑思考,好像也只能试,即先随意找一条路,并且让最大流为这条路线的最小额定流(这个应该是显然的,否则会烧坏),然后再看还能不能走其他的路,如果还有其他路并且还有路没有达到该线路的最小额定(电流),那么就继续增加最大流,显然更优。但是我们如何能够保证自己找到的路线是最优的呢?即我们如果之前走错了,现在想要反悔应该怎么做呢?
假设我们现在先用bfs随意找出了一条路线,并且让最大流更新为这条路线的最小额定流,然后第二次再去找,发现找到一半后半程的路线和上一条路线重合,而且因为上一条路线已经达到了容量,所以我们无法再增加流量。假如上一条路线还有其他支路到达汇点,而且可行,那么我们显然是想推掉上一条路线和这条路线重合的部分然后两条路线分别到达,但是我们如何推掉呢?我们这里引入一种方法:增加反向边——即如果我们选定了一条路线,为了方便以后更改,我们给这条路线全部加上容量等于这条路线最大流量的反向边。
现在来看为什么加上反向边就可以修改了:
加入我们有如图所示关系,并且第一次找到的路线为:1--2--3--4
然后我们进行第二次寻找,发现找到1--3后就不能再进行了,可是从直觉上来看显然最大流为1--2--4和1--3--4,显然不能进行是不对的。
但是假如我们在第一次寻找的时候都加上了反向边:
如图所示:第二次我们再进行查找的时候就可以走1--3--2--4,加上上一条路线,即为最优。
那么,为什么这样做就对了呢?我们可以这样理解:反向边就好像是退回了一条边,反向3--2抵消了上一个路线中的2--3,实际路线仍然是1--2--4和1--3--4
但是,如何保证这种抵消的正确性呢?我们不难发现:上一条路线和这一条路线的连接点就在那一条反向边,通过设置反向边的容量,我们保证了抵消这条边后剩下的部分可以和上一条路线连接而且不会发生错误。
实际实现:
以上就是理解部分,通过这种思想设计出了edmonds-Karp算法:
题目:
Drainage Ditches
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1507 Accepted Submission(s): 701
Problem DescriptionEvery 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
#include<cstring>
#include<cstdio>
#include<climits>
#include<cmath>
#include<queue>
using namespace std;
const int MAXN=205;
int n,m;
int a[MAXN][MAXN];
int pre[MAXN];
int vis[MAXN];
int u,v,w;
void update_network(int u,int flow)
{
while(pre[u]!=-1)
{
a[pre[u]][u]-=flow;
a[u][pre[u]]+=flow;
u=pre[u];
}
}
int find_new(int s,int t)
{
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
vis[s]=1;
int min=INT_MAX;
queue<int> q;
q.push(s);
while(!q.empty())
{
int cur=q.front(); q.pop();
if(cur==t) break;
for(int i=1;i<=m;i++)
{
if(vis[i]==0 && a[cur][i]!=0)
{
q.push(i);
min=(min<a[cur][i]?min:a[cur][i]);
pre[i]=cur;
vis[i]=1;
}
}
}
if(pre[t]==-1) return 0;
return min;
}
int edmonds_karp(int s,int t)
{
int new_flow=0;
int max_flow=0;
do
{
new_flow=find_new(s,t);
update_network(t,new_flow);
max_flow+=new_flow;
}while(new_flow!=0);
return max_flow;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(a,0,sizeof(a));
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&u,&v,&w);
a[u][v]+=w;
}
printf("%d
",edmonds_karp(1,m));
}
return 0;
}
以上是关于网络流初步的主要内容,如果未能解决你的问题,请参考以下文章