网络流最大流最小割算法

不得不说网络流算法是很让人无语的算法,要想高效率竟然要非递归实现深搜,很无奈,到现在还是在低效率中挣扎!

最大流算法的证明就不说了,无非就是最大流最小割定理的推导,定理描述如下:

对于任意给定的网络D=(V,A,C),从出发点vs到收点vt的最大流的流量必等于分割的最小截集的容量!

至于截集,定义为:

给定网络D=(V,A,C),若点集V被分割成两个非空集合V1和V2,使得V=V1+V2,V1

V2=φ(空集),且vs∈V1,vt∈V2,则把始点在V1,终点在V2的弧的集合称为分离vs和vt

一个截集

然后,网络流算法最重要的增广链,正式定义为:

设 f = {Fij}是网络D=(V,A,C)上的一个可行流,u 是从 Vs到 Vt的一条链,若u 满足下列条件:

(1)在弧 (vi,vj)∈μ+上,即 u+中的每一条弧都是非饱和弧;

(2)在弧 (vi,vj)∈μ-上,即u- 中的每一条弧都是非零流弧。

则称 是关于 的一条增广链

最大流就是不断的找增广链,直到找不到增广链为止!

朴素的有Ford —— Fulkerson标号法,就是每次从源点开始找增广链,然后更新网络,再找增广链,再更新。。。

伪代码可以表示为:

void Ford_Fulkerson()

{

int max_l = 0;

while (存在增广链)

{

max_l += 可更新流量;

更新残余网络;

}

}

另外网络流算法多种多样,比如dinic,有兴趣可以学习学习!

代码如下:

#include <iostream>
#include <cstring>
#include <cstdlib>

using namespace std;

const int Max = 225;
const int oo = 210000000;

int n,m,c[Max][Max],r[Max][Max],source,sink,nc,np;
int dis[Max],block[Max];

void initialize()// BFS建立层次图,
{
int q[Max],head = 0, tail = 0;
for(int i = 0; i <= sink; i++) dis[i] = oo;
q[++head] = sink;
dis[sink] = 0;
while(tail < head)
{
int u = q[++tail], v;
for(v = 0; v <= sink; v++)
{
if(dis[v] == oo && r[v][u] > 0)
{
dis[v] = dis[u] + 1;
q[++head] = v;
}
}
}

}

int dinic()
{
initialize();
int top = source, pre[Max], flow = 0, i, j, k, low[Max];//top是最短增广路最前面一个节点
memset(low,0,sizeof(low));
memset(block,0,sizeof(block));
while(dis[source] != oo)// Dinic算法结束条件:从源点到汇点没有路
{
bool flag = false;
low[source] = oo;
for(i = 0; i <= sink; i++)//找admissible arc
{
if(r[top][i] > 0 && dis[top] == dis[i] + 1 && !block[i])
{
flag = true;
break;
}
}
if(flag)// 如果找到
{
low[i] = r[top][i];// low保存到当前节点的最小容量
if(low[i] > low[top]) low[i] = low[top];//更新
pre[i] = top; top = i;
if(top == sink)//找到路
{
flow += low[sink];
j = top;
while(j != source)//回溯更新残流网络
{
k = pre[j];
r[k][j] -= low[sink];
r[j][k] += low[sink];
j = k;
}
top = source;//从新找增广路
memset(low,0,sizeof(low));
}
}
else//否则阻塞当前点
{
block[top] = 1;
if(top != source) top = pre[top];//回溯
}
if(block[source])//如果源点被阻塞了就从新建立层次图
{
initialize();
memset(block,0,sizeof(block));
}
}
return(flow);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值