当前位置:
文档之家› 网络流算法和PASCAL程序
网络流算法和PASCAL程序
网络流算法及其应用
网络流
网络流 network flows网络流的理论和应用在不断发展,出现了具有增益的流、多终端流、多商品流以及网络流的分解与合成等新课题。网络流的应用已遍及通讯、运输、电力、工程规划、任务分派、设备更新以及计算机辅助设计等众多领域。
目录
定义
图论中的一种理论与方法,研究网络上的一类最优化问题。1955年,T.E. 哈里斯在研究铁路最大通量时首先提出在一个给定的网络上寻求两点间最大运输量的问题。1956年,L.R. 福特和 D.R. 富尔克森等人给出了解决这类问题的算法,从而建立了网络流理论。所谓网络或容量网络指的是一个连通的赋权有向图 D=(V、E、C),其中V 是该图的顶点集,E是有向边(即弧)集,C是弧上的容量。此外顶点集中包括一个起点和一个终点。网络上的流就是由起点流向终点的可行流,这是定义在网络上的非负函数,它一方面受到容量的限制,另一方面除去起点和终点以外,在所有中途点要求保持流入量和流出量是平衡的。如果把下图看作一个公路网,顶点v1 (v6)
表示6座城镇,每条边上的权数表示两城镇间的公路长度。现在要问:若从起点v1将物资运送到终点v6去,应选择那条路线才能使总运输距离最短???这样一类问题称为最短路问题。如果把上图看作一个输油管道网, v1 表示发送点,v6表示接收点,其他点表示中转站,各边的权数
寻找通路的时候可以用DFS,BFS最短路等算法。就这两者来说,BFS要比DFS快得多,但是编码量也会相应上一个数量级。
增广路方法可以解决最大流问题,然而它有一个不可避免的缺陷,就是在极端情况下每次只能将流扩大1(假设容量、流为整数),这样会造成性能上的很大问题,解决这个问题有一个复杂得多的算法,就是预推进算法。
2、push label,直译为“预推进”算法。
3、压入与重标记(Push-Relabel)算法
除了用各种方法在剩余网络中不断找增广路(augmenting)的
Ford-Fulkerson系的算法外,还有一种求最大流的算法被称为压入与重标记(Push-Relabel)算法。它的基本操作有:压入,作用于一条边,将边的始点的预流尽可能多的压向终点;重标记,作用于一个点,将它的高度(也就是label)设为所有邻接点的高度的最小值加一。Push-Relabel系的算法普遍要比Ford-Fulkerson系的算法快,但是缺点是相对难以理解。
Relabel-to-Front使用一个链表保存溢出顶点,用Discharge操作不断使溢出顶点不再溢出。Discharge的操作过程是:若找不到可被压入的临边,则重标记,否则对临边压入,直至点不再溢出。算法的主过程是:首先将源点出发的所有边充满,然后将除源和汇外的所有顶点保存在一个链表里,从链表头开始进行Discharge,如果完成后顶点的高度有所增加,则将这个顶点置于链表的头部,对下一个顶点开始Discharge。
Relabel-to-Front算法的时间复杂度是O(V^3),还有一个叫Highest Label Preflow Push的算法复杂度据说是O(V^2*E^0.5)。我研究了一下HLPP,感觉它和Relabel-to-Front本质上没有区别,因为Relabel-to-Front 每次前移的都是高度最高的顶点,所以也相当于每次选择最高的标号进行更新。还有一个感觉也会很好实现的算法是使用队列维护溢出顶点,每次对pop出来的顶点discharge,出现了新的溢出顶点时入队。
Push-Relabel类的算法有一个名为gap heuristic的优化,就是当存在一个整数0k的顶点v 做更新,若它小于V+1就置为V+1。
cpp程序:
#include
const long maxn=1000+10;
const long maxm=440000+100;
const long maxnum=100000000;
long
n,m,s=0,tot=0,list[maxn],p[maxn],g[maxn],gg[maxn],dis[maxn];
bool mark[maxn];
struct node
{
long k,f,c,next,g;
}d[maxm<<1];
void insert(long u,long v,long c)
{
d[tot].k=v;
d[tot].f=0;
d[tot].c=c;
d[tot].next=g;
g=tot;
d[tot].g=tot+1;
tot++;
d[tot].k=u;
d[tot].f=0;
d[tot].c=0;
d[tot].next=g[v];
g[v]=tot;
d[tot].g=tot-1;
tot++;
}
void bfs()
{
long x,u,v,h,t;
for (long i=0;idis=0;
h=0;
t=1;
list[1]=0;
编辑本段最小费用最大流
一.Ford和Fulkerson迭加算法.
基本思路:把各条弧上单位流量的费用看成某种长度,用求解最短路问题的方法确定一条自V1至Vn的最短路;在将这条最短路作为可扩充路,用求解最大流问题的方法将其上的流量增至最大可能值;而这条最短路上的流量增加后,其上各条弧的单位流量的费用要重新确定,如此多次迭代,最终得到最小费用最大流.
迭加算法:
1) 给定目标流量F或∞,给定最小费用的初始可行流=0
2) 若V(f)=F,停止,f为最小费用流;否则转(3).
3) 构造相应的新的费用有向图W(fij),在W(fij)寻找Vs到Vt的最小费用有向路P(最短路),沿P增加流f的流量直到F,转(2);若不存在从Vs到Vt的最小费用的有向路P,停止.f就是最小费用最大流.
具体解题步骤:
设图中双线所示路径为最短路径,费用有向图为W(fij).
在图(a)中给出零流 f,在图(b)中找到最小费用有向路,修改图(a)中的可行流,δ=min{4,3,5}=3,得图(c),再做出(c)的调整容量图,再构造相应的新的最小费用有向路得图(d), 修改图(c)中的可行流, δ=min{1,1,2,2}=1,得图(e),以此类推,一直得到图(h),在图(h)中以无最小费用有向路,停止,
经计算:
图(h)中最小费用=1*4+3*3+2*4+4*1+1*1+4*2+1*1+3*1=38
图(g)中最大流=5
最大流问题仅注意网络流的流通能力,没有考虑流通的费用。实际上费用因素是很重要的。例如在交通运输问题中,往往要求在完成运输任务的前提下,寻求一个使总运输费用最省的运输方案,这就是最小费用流问题。如果只考虑单位货物的运输费用,那么这个问题就变成最短路问题。由此可见,最短路问题是最小费用流问题的基础。现已有一系列求最短路的成功方法。最小费用流(或最小费用最大流)问题,可以交替使用求解最大流和最短路两种方法,通过迭代得到解决。
二.圈算法:
1) 利用Ford和Fulkson标号算法找出流量为F(<=最大流)的流f.
2) 构造f对应的调整容量的流网络N'(f).
3) 搜索N'(f)中的负费用有向图C(Floyd算法),若没有则停止,否则转
(4).
4) 在C上找出最大的循环流,并加到N上去,同时修改N'(F)中C的容量,转(3).
具体解题步骤:
利用Ford和Fulkson标号算法,得网络的最大流F=5,见图(a),由图(a)构造相应的调整容量的流网络(b),图(b)中不存在负费用有向图,故停止.经计算:
图(b)中最小费用= 4*1+3*1+1*1+3*3+4*2+1*1+4*1+2*4=38
图(a)中最大流为F=5
Type
szbest=record
v,l:integer;
end;
szmap=record
c,f,w:integer;
end;
Var
map:array[0..1000,0..1000] of szmap;
best:array[0..1000] of szbest;
i,j,ans,n,k,a,b,c,d,s,t:integer;
Function find:boolean;
var i,j:integer;
flag:boolean;
begin
for i:=1 to n do best.v:=maxint;
best[s].v:=0;
repeat
flag:=true;
for i:=1 to n do
if best.vfor j:=1 to n do
if (map[i,j].f