#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<limits.h>
#include<math.h>
#include<queue>
#include<algorithm>
using namespace std;
#define maxn 205
#define inf 0x7fffffff
int path[maxn][maxn];//记录残留网络的容量
int flow[maxn];//标记从原点到当前节点实际还剩多少流量
int pre[maxn];//标记在这条路径上当前节点的前驱,同时标记该节点是否在队列中
int n,m;
queue<int>q;
int bfs(int start,int end)
{
while(!q.empty()) //清空队列
q.pop();
memset(pre,-1,sizeof(pre));
pre[start]=0;
q.push(start);
flow[start]=inf;
while(!q.empty())
{
int now=q.front();
q.pop();
if(now==end)//找到了增广路径
break;
for(int i=1;i<=m;i++)
{
if(i==now)
continue;
if(path[now][i]>0 && pre[i]==-1)
{
pre[i]=now;
flow[i]=min(path[now][i],flow[now]);
q.push(i);
}
}
}
if(pre[end]==-1)//残留网络中不存在增广路
return 0;
else
return flow[end];
}
int maxflow(int start,int end)
{
int ans;
int sum=0;
while((ans=bfs(start,end))!=0)
{
int k=end;//利用前驱寻找路径
while(k!=start)
{
int last=pre[k];
path[last][k]-=ans;
path[k][last]+=ans;//正向最小流量等于方向最大流量(自己的理解)
k=last;
}
sum+=ans;
}
return sum;
}
int main()
{
int i,j;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(path,0,sizeof(path));
memset(flow,0,sizeof(flow));
int a,b,c;
for(i=1;i<=n;i++)
{
scanf("%d%d%d",&a,&b,&c);
if(a==b)//考虑起点和终点相同的情况
continue;
path[a][b]+=c;//相同的起点和终点之间不止一条边
}
printf("%d\n",maxflow(1,m));
}
}
网络流(最大流+模板)
原创
©著作权归作者所有:来自51CTO博客作者mb6131cb1bd1974的原创作品,请联系作者获取转载授权,否则将追究法律责任
一、网络流的基本概念
先来看一个实例。
现在想将一些物资从S运抵T,必须经过一些中转站。连接中转站的是公路,每条公路都有最大运载量。如下图:
每条弧代表一条公路,弧上的数表示该公路的最大运载量。最多能将多少货物从S运抵T?
这是一个典型的网络流模型。为了解答此题,我们先了解网络流的有关定义和概念。
若有向图G=(V,E)满足下列条件:
1、
有且仅有一个顶点S,它的入度为零,即d-(S) = 0,这个顶点S便称为源点,或称为发点。
2、
有且仅有一个顶点T,它的出度为零,即d+(T) = 0,这个顶点T便称为汇点,或称为收点。
3、 每一条弧都有非负数,叫做该边的容量。边(vi, vj)的容量用cij表示。
则称之为网络流图,记为G = (V, E, C)
譬如图5-1就是一个网络流图。
1.可行流
对于网络流图G,每一条弧(i,j)都给定一个非负数fij,这一组数满足下列三条件时称为这网络的可行流,用f表示它。
(1) 每一条弧(i,j)有fij≤cij。
(2) 除源点S和汇点T以外的所有的点vi,恒有:
该等式说明中间点vi的流量守恒,输入与输出量相等。
(3) 对于源点S和汇点T有:
这里V(f)表示该可行流f的流量。
例如对图5-1而言,它的一个可行流如下:
流量V(f) = 5。
2.可改进路
给定一个可行流f=。若fij = cij,称<vi, vj>为饱和弧;否则称<vi, vj>为非饱和弧。若fij = 0,称<vi, vj>为零流弧;否则称<vi, vj>为非零流弧。
定义一条道路P,起点是S、终点是T。把P上所有与P方向一致的弧定义为正向弧,正向弧的全体记为P+;把P上所有与P方向相悖的弧定义为反向弧,反向弧的全体记为P-。
譬如在图5-1中,P = (S, V1, V2, V3, V4, T),那么
P+ = {<S, V1>, <V1, V2>, <V2, V3>, <V4, T>}
P- = {<V4, V3>}
给定一个可行流f,P是从S到T的一条道路,如果满足:
那么就称P是f的一条可改进路。(有些书上又称:可
增广轨)之所以称作“可改进”,是因为可改进路上弧的流量通过一定的规则修改,可以令整个流量放大。具体方法下一节会重点介绍,此不赘述。
3.割切
要解决网络最大流问题,必须先学习割切的概念和有关知识。
G = (V, E, C)是已知的网络流图,设U是V的一个子集,W = V\U,满足S U,T W。即U、W把V分成两个不相交的集合,且
源点和汇点分属不同的集合。
对于弧尾在U,弧头在W的弧所构成的集合称之为割切,用(U,W)表示。把割切(U,W)中所有弧的容量之和叫做此割切的容量,记为C(U,W),即:
例如图5-1中,令U = {S, V1},则W = {V2, V3, V4, T},那么
C(U, W) = <S, V2> + <V1, V2> + <V1, V3>+<V1, V4>=8+4+4+1=17
定理:对于已知的网络流图,设任意一可行流为f,任意一割切为(U, W),必有:V(f) ≤ C(U, W)。
通俗简明的讲:“最大流小于等于任意割”。这是“流理论”里最基础最重要的定理。整个“流”的理论系统都是在这个定理上建立起来的,必须特别重视。
下面我们给出证明。
网络流、可改进路、割切都是基础的概念,应该扎实掌握。它们三者之间乍一看似乎风马牛不相干,其实内在联系是十分紧密的。
二、求最大流
何谓最大流?首先它必须是一个可行流;其次,它的流量必须达到最大。这样的流就称为最大流。譬如对图5-1而言,它的最大流如下:
下面探讨如何求得最大流。
在定义“可改进路”概念时,提到可以通过一定规则修改“可改进路”上弧的流量,可以使得总流量放大。下面我们就具体看一看是什么“规则”。
对可改进路P上的弧<vi, vj>,分为两种情况讨论:
第一种情况:<vi, vj>∈P+,可以令fij增加一个常数delta。必须满足fij + delta ≤ cij,即delta ≤ cij – fij。
第二种情况:<vi, vj>∈P-,可以令fij减少一个常数delta。必须满足fij - delta ≥ 0,即delta ≤ fij
根据以上分析可以得出delta的计算公式:
因为P+的每条弧都是非饱和弧,P-的每条弧都是非零流弧,所以delta > 0。
容易证明,按照如此规则修正流量,既可以使所有中间点都满足“流量守恒”(即输入量等于输出量),又可以使得总的流量有所增加(因为delta > 0)。
因此我们对于任意的可行流f,只要在f中能找到可改进路,那么必然可以将f改造成为流量更大的一个可行流。我们要求的是最大流,现在的问题是:倘若在f中找不到可改进路,是不是f就一定是最大流呢?
答案是肯定的。下面我们给出证明。
定理1 可行流f是最大流的
充分必要条件是:f中不存在可改进路。
证明:
首先证明必要性:已知最大流f,求证f中不存在可改进路。
若最大流f中存在可改进路P,那么可以根据一定规则(详见上文)修改P中弧的流量。可以将f的流量放大,这与f是最大流矛盾。故必要性得证。
再证明充分性:已知流f,并且f中不存在可改进路,求证f是最大流。
我们定义顶点集合U, W如下:
(a) S∈U,
(b) 若x∈U,且fxy<cxy,则y∈U;
若x∈U,且fyx>0,则y∈U。
(这实际上就是可改进路的构造规则)
(c) W = V \ U。
由于f中不存在可改进路,所以T∈W;又S∈U,所以U、W是一个割切(U, W)。
按照U的定义,若x∈U,y∈W,则fxy = cxy。若x∈W,y∈U,则fxy = 0。
所以,
又因 v(f)≤C(U,W)
所以f是最大流。得证。
根据充分性证明中的有关结论,我们可以得到另外一条重要定理:
最大流最小割定理:最大流等于最小割,即max V(f) = min C(U, W)。
至此,我们可以轻松设计出求最大流的算法:
step 1. 令所有弧的流量为0,从而构造一个流量为0的可行流f(称作零流)。
step 2. 若f中找不到可改进路则转step 5;否则找到任意一条可改进路P。
step 3. 根据P求delta。
step 4. 以delta为改进量,更新可行流f。转step 2。
step 5. 算法结束。此时的f即为最大流。
下面给出一道题目便于理解,并附上代码

提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
java获取当月最大日
java获取当月最大日
System java 字段 -
【模板】网络最大流
【模板】网络最大流 题目描述如题,给出一个网络图,以及其源点和汇格式:一行,...
#include #define 数据 -
网络流—最大流
第一次学习网络流,发表一下自己的看法。 在这篇博文当中主要讲一讲3个最大流算法:EK算法,Dinic算法和SAP算法。
#include 最大流 #define -
网络流 最大流模板算法 FF算法 Dinic算法
tdc++.h>using namespace std;const...
网络流 最大流 最大流模板算法 FF算法 Dinic算法