将用PACASL写的 网络最大流算法 翻译成c/c++的,谢谢

fjxszx_hss 2008-03-18 03:46:49


那位能将下面这段程序翻译成c/c++的,谢谢!!


最大网络流

最大流问题实际上是求一可行流{fij},使得v(f达到最大。定理1中证明实际上已为我们提供了寻求网络中最大流的一个方 法。若给了一个可行流f,只要判断N中有无关于f的增广路径,如果有增广路径,则按定理1的必要性证明中的办法,改进f, 得到一个沈量增大的新的可行流;如果没有增广路径,则得到最大流。而利用定理1充分性证明中定义A*的办法,可以根据vt是 否属于A*来判断N中有无关于f的增广路径。
下面我们用顶点标号法来定义A*,在标号过程中,有标号的顶点表示是A*中的点,没有标号的点表示不是A*中的点。如 果vt有标号,则说明找到了一条增广路径;如果标号过程进行不下去,而vt又还没有标号,则说明不存在增广路径,于是得到了最大流,同时也得到了一个最小割集。

1)寻求最大流的标号法(Ford,Fulkerson)
从一个可行流(一般取零流)开始,不断进行以下的标号过程与调整过程,直到找不到关于f的可增广路径为止。
(1)标号过程
在这个过程中,网络中的点分为已标号点和未标号点,已标号点又分为已检查和未检查两种。每个标号点的标号信息表示两个 部分:第一标号表明它的标号从哪一点得到的,以便从vt开始反向追踪找出也增广路径;第二标号是为了表示该顶点是否已检查过。
标号开始时,给vs标上(s,0),这时vs是标号但末检查的点,其余都是未标号的点,记为(0,0)。
取一个标号而未检查的点vi,对于一切未标号的点vj:
A.对于弧(vi,vj),若fij<cij,则给vj标号(vi,0),这时,vj点成为标号而未检查的点。
B.对于弧(vi,vj),若fji>0,则给vj标号(-vi,0),这时,vj点成为标号而未检查的点。
于是vi成为标号且已检查的点,将它的第二个标号记为1。重复上述步骤,一旦vt被标上号,表明得到一条从vi到vt的增广路径p,转入调整过程。
若所有标号都已检查过去,而标号过程进行不下去时,则算法结束,这时的可行流就是最大流。
(2)调整过程
从vt点开始,通过每个点的第一个标号,反向追踪,可找出增广路径P。例如设vt的第一标号为vk(或-vk),则弧(vk,vt)(或 相应地(vt,vk))是p上弧。接下来检查vk的第一标号,若为vi(或-vi),则找到(vi,vk)(或相应地(vk,vi))。再检查vi的第一 标号,依此类推,直到vs为止。这时整个增广路径就找到了。在上述找增广路径的同时计算Q:
Q=min{min(cij-fij),minf*ij}
对流f进行如下的修改:
f'ij = fij+Q (vi,vj)∈ P的前向弧的集合
f'ij = fij-Q (vi,vj)∈ P的后向弧的集合
f'ij = f*ij (vi,vj)不属于P的集合
接着,清除所有标号,对新的可行流f’,重新进入标号过程。

2)求最大流标号法的具体实现
(1)数据结构
对于网络N,它首先是一个有向图N(V,E),对于有向图一般我们用邻接矩阵表示,为了存放流f,这个有向图的弧上信息包含两个部分,分别是弧的容量与弧上的流。具体的数据结构如下:
type
nettype=record
c,f:integer;
end;
var
g:array[O..maxn,O..maxn] of nettype;
为了找到增广路径,我们要有对每个的顶点标号,第一个标号L表明它的标号从哪一点得到的,第二标号p是为了表示该顶
点是否已检查过。具体数据结构如下:
type
nodetype=record
l,p:integer;
end;
var
Lt:array[O..maxn] of nodetype;
(2)参考程序
Program Max_Stream;
Const Maxn=20;
type
nettype=record
C,F:integer;
end;
nodetype=record
L,P:integer;
end;
var
Lt:array[O..maxn] of nodetype;
G:Array[0..Maxn,0..Maxn] of Nettype;
N,S,T:integer;
F:Text;

Procedure Init;{初始化过程,读人有向图,并设置流为0}
Var Fn :String;
I,J :Integer;
Begin
Write( 'Graph File = ' ); Readln(Fn);
Assign(F,Fn);
Reset(F);
Readln(F,N);
Fillchar(G,Sizeof(G) ,0);
Fillchar(Lt,Sizeof(Lt),O);
For I:=1 To N Do
For J:=1 To N Do Read(F,G[I,J].C);
Close(F);
End;

Function Find: Integer; {寻找已经标号未检查的顶点}
Var I: Integer;
Begin
I:=1;
While (I<=N) And Not((Lt[I].L<>0)And(Lt[I].P=0)) Do Inc(I);
If I>N Thru Find:= 0 Else Find:= I;
End;

Function Ford(Var A: Integer):Boolean;
Var {用标号法找增广路径,并求修改量A}
I,J,M,X:Integer;
Begin
Ford:=True;
Fillchar(Lt,Sizeof(Lt),0);
Lt[S].L:=S;
Repeat
I:= Find;
If i=0 Then Exit;
For J:=1 To N Do
If (Lt[J].L= 0)And((G[I,J].C<>0)or(G[J,I].C<>0)) Then
Begin
if (G[I,J].F<G[I,J].C) Then Lt[J].L:= I;
If (G[J,I].F>0) Then Lt[J].L:= I;
End;
Lt[I].P:=1;
Until (Lt[T].L<>0);
M:=T;A:=Maxint;
Repeat
J:=M;M:=Abs(Lt[J].L);
If Lt[J].L<0 Then X:= G[J,M].F;
If Lt[J].L>0 Then X:= G[M,J].C- G[M,J].F;
If X<A Then A:= X;
Until M= S;
Ford:=False;
End;

Procedure Change(A: Integer);{调整过程}
Var M, J: Integer;
Begin
M:= T;
Repeat
J:=M;M:=Abs(Lt[J].L);
If Lt[J].L<0 Then G[J,M].F:=G[J,M].F-A;
If Lt[J].L>0 Then G[M,J].F:=G[M,j].F+A;
Until M=S;
End;

Procedure Print; {打印最大流及其方案}
VAR
I ,J: Integer;
Max: integer;
Begin
Max:=0;
For I:=1 To N DO
Begin
If G[I,T].F<>0 Then Max:= Max + G[I,T].F;
For J:= 1 To N Do
If G[I,J].F<>0 Then Writeln( I, '-> ' ,J,' ' ,G[I,J].F);
End;
Writln(’TheMaxStream‘’,Max);
End;

Procedure Process;{求最大流的主过程}
Var Del:Integer;
Success:Boolean;
Begin
S:=1;T:=N;
Repeat
Success:=Ford(Del);
If Success Then Print
Else Change(Del);
Until Success;
End;

Begin {Main Program}
Init;
Process;
End. {源程序及数据文件见下}
以上标号法求最大流的算法,只能适用于网络中的任意两点之间只有一条弧的情况,若任意两点之间有多条弧,则我们可以通过在这些弧中的每条弧上设置一个虚拟点,转化成任意两点间只有一条弧情况。

源程序:

Program Max_Stream;
Const Maxn=20;
type
nettype=record
C,F:integer;
end;
nodetype=record
L,P:integer;
end;
var
Lt:array[0..maxn] of nodetype;
G:Array[0..Maxn,0..Maxn] of Nettype;
N,S,T:integer;
F:Text;

Procedure Init;{初始化过程,读人有向图,并设置流为0}
Var Fn :String;
I,J :Integer;
Begin
Write( 'Graph File = ' ); Readln(Fn);
Assign(F,Fn);
Reset(F);
Readln(F,N);
Fillchar(G,Sizeof(G) ,0);
Fillchar(Lt,Sizeof(Lt),0);
For I:=1 To N Do
For J:=1 To N Do Read(F,G[I,J].C);
Close(F);
End;

Function Find: Integer; {寻找已经标号未检查的顶点}
Var I: Integer;
Begin
I:=1;
While (I<=N) And Not((Lt[I].L<>0)And(Lt[I].P=0)) Do Inc(I);
If I>N Then Find:= 0 Else Find:= I;
End;

Function Ford(Var A: Integer):Boolean;
Var {用标号法找增广路径,并求修改量A}
I,J,M,X:Integer;
Begin
Ford:=True;
Fillchar(Lt,Sizeof(Lt),0);
Lt[S].L:=S;
Repeat
I:= Find;
If i=0 Then Exit;
For J:=1 To N Do
If (Lt[J].L= 0)And((G[I,J].C<>0)or(G[J,I].C<>0)) Then
Begin
if (G[I,J].F<G[I,J].C) Then Lt[J].L:= I;
If (G[J,I].F>0) Then Lt[J].L:= I;
End;
Lt[I].P:=1;
Until (Lt[T].L<>0);
M:=T;A:=Maxint;
Repeat
J:=M;M:=Abs(Lt[J].L);
If Lt[J].L<0 Then X:= G[J,M].F;
If Lt[J].L>0 Then X:= G[M,J].C- G[M,J].F;
If X<A Then A:= X;
Until M= S;
Ford:=False;
End;

Procedure Change(A: Integer);{调整过程}
Var M, J: Integer;
Begin
M:= T;
Repeat
J:=M;M:=Abs(Lt[J].L);
If Lt[J].L<0 Then G[J,M].F:=G[J,M].F-A;
If Lt[J].L>0 Then G[M,J].F:=G[M,j].F+A;
Until M=S;
End;

Procedure Print; {打印最大流及其方案}
VAR
I ,J: Integer;
Max: integer;
Begin
Max:=0;
For I:=1 To N DO
Begin
If G[I,T].F<>0 Then Max:= Max + G[I,T].F;
For J:= 1 To N Do
If G[I,J].F<>0 Then Writeln( I, '-> ' ,J,' ' ,G[I,J].F);
End;
Writeln('The Max Stream=',Max);
End;

Procedure Process;{求最大流的主过程}
Var Del:Integer;
Success:Boolean;
Begin
S:=1;T:=N;
Repeat
Success:=Ford(Del);
If Success Then Print
Else Change(Del);
Until Success;
End;

Begin {Main Program}
Init;
Process;
End.
数据文件的内容:

4
0 3 4 5 0 0 0 4 0 5 0 3 0 0 0 0


...全文
342 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

3,423

社区成员

发帖
与我相关
我的任务
社区描述
其他开发语言 其他开发语言
社区管理员
  • 其他开发语言社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧