B).对于弧(vi,vj),若fji>0,则给vj标号(-vi,0),vj点成为标号而未检查的点。
然后找到下一个标号而未检查的点,重复上述步骤,一旦vt被标上号,表明得到一条从vi到vt的增广路径p,转入调整过程。
若所有标号都已检查过去,而标号过程进行不下去时,则算法结束,这时的可行流就是最大流。
(2)调整过程
从vt点开始,通过每个点的第一个标号,反向追踪(根据结点的From信息),可找出增广路P。
直到vs为止。
这时整个增广路径就找到了。
在上述找增广路径的同时计算调整值:
min{min(cij-fij),min(fij)}
a、初始化结果:
输入的结果为红色字体
b、初始化后的到结果:
红框中得到的图的关系与课本例题中的一样!
所以创建图形正确!
c、最后得到的结果:
6x6的矩阵中,每一行中紫色表示的是有边相连的顶点。
其中的两个值,第一个代表的是容量,第二个值代表的是流量。
得到的结果与课本中例题的结果一致。
所以编写的程序正确。
五、实验总结
通过编程来实现的时候,发现手工做的话容易实现,同时在手工做的时候容易忽略一些细节性的东西。
而通过编程来实现的话需要把一些忽略的细节重视起来。
同时有了前面两个实验的铺垫,这个实验实现起来也是得心应手的。
六、源代码
源代码如下:
//图的顶点结构如下:
//-----------------------------------
//|vex|formerNode|flowsDiff|mark|
//-----------------------------------
//图的边的结构如下:
//----------------
//|weight|flows|
//----------------
#include
#include
#include
usingnamespacestd;
#defineMax_vex100
#defineM1000
//SetTextC1是原来的颜色
//SetTextC2是设置的输出输入颜色
#defineSetTextC1SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE)
#defineSetTextC2SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN)
#defineSetTextC3SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN|FOREGROUND_BLUE)
#defineSetTextC4SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED)
#defineSetTextC5SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_BLUE)
#defineSetTextC6SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE)
#defineSetTextC7SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN)
classArcll{//边上值
public:
doubleweight;//容量
doubleflows;//流量
};
enumMark{n_mark,marking,h_marked};//分别代表没有标记,已经标记_未检查,已经标记_检查
classVex{//顶点值
public:
stringvexs;//顶点名称
stringformerVex;
doubleflowsDiff;//流量的差值且最小
Markmark;
};
classGraphics{//创建一个图的类
private:
intvexnum;//顶点数
intarcnum;//边数
Vexvexs[Max_vex];//存储定点名称
Arcllarcs[Max_vex][Max_vex];//边数
public:
voidCreateGraphics(Graphics&G);//创建一个图
intLocateIndex(GraphicsG,stringv);//寻找下标
voidMark_getMaxstream(Graphics&G);
boolMark_FindMaxstream(Graphics&G);//标号法寻找最大流
boolMark_Node(Graphics&G,inti);//标记的方法
intCheckMarkNode(Graphics&G,inti);
};
//方法实现
//找到相应顶点的下标
intGraphics:
:
LocateIndex(GraphicsG,stringv){
inti=0;
for(i=0;iif(G.vexs[i]pare(v)==0){
returni;
}
}
return-1;
}
//创建一个有向图
voidGraphics:
:
CreateGraphics(Graphics&G){
inti,j,k;
stringVi,Vj;
doublew,f;//容量、流量
SetTextC1;
cout<<"-------------------------创建有向图的存储-------------------------------"<cout<<"请输入顶点数:
";
SetTextC4;//设置颜色
cin>>G.vexnum;
SetTextC1;//设置颜色
cout<<"请输入图的边数:
";
SetTextC4;
cin>>G.arcnum;
SetTextC1;
cout<<"请输入顶点名:
";
SetTextC4;
for(i=0;icin>>G.vexs[i].vexs;
G.vexs[i].formerVex="";
G.vexs[i].mark=n_mark;
}
SetTextC1;
for(i=0;ifor(j=0;jG.arcs[i][j].weight=M;
G.arcs[i][j].flows=-1;
}
}
for(k=0;kcout<<"请输入第"<";
SetTextC4;
cin>>Vi>>Vj>>w>>f;
SetTextC1;
i=LocateIndex(G,Vi);
j=LocateIndex(G,Vj);
if(i==-1||j==-1){
cout<<"输入错误!
请检查..."<return;
}
G.arcs[i][j].weight=w;
G.arcs[i][j].flows=f;
}
cout<cout<<"各顶点的关系:
"<SetTextC2;
for(i=0;iif(i==0){
cout<<"\t\t"<}else{
cout<<"\t"<}
}
cout<SetTextC3;
for(i=0;iSetTextC2;
cout<<"\t"<SetTextC3;
for(j=0;jif(G.arcs[i][j].weight==M){
SetTextC6;
cout<<"\t"<<"";
SetTextC3;
}else{
cout<<"\t<"<";
}
}
cout<}
SetTextC1;
cout<"<}
//-------------------------标号法寻找最大流-------------------------
voidGraphics:
:
Mark_getMaxstream(Graphics&G){
boolb=true;
inti,j;
G.CreateGraphics(G);//创建图的存储结构
cout<<"-------------------------标号法寻找最大流-------------------------------"<while(b){
b=Mark_FindMaxstream(G);
if(!
b){
break;
}
cout<<"调整后:
"<SetTextC2;
for(i=0;iif(i==0){
cout<<"\t\t"<}else{
cout<<"\t"<}
}
cout<SetTextC3;
for(i=0;iSetTextC2;
cout<<"\t"<SetTextC3;
for(j=0;jif(G.arcs[i][j].weight==M){
SetTextC6;
cout<<"\t"<<"";
SetTextC3;
}else{
cout<<"\t<"<";
}
}
cout<}
SetTextC1;
}
if(!
b){
cout<<"找到了!
最后结果为:
"<SetTextC2;
for(i=0;iif(i==0){
cout<<"\t\t"<}else{
cout<<"\t"<}
}
cout<SetTextC3;
for(i=0;iSetTextC2;
cout<<"\t"<SetTextC5;
for(j=0;jif(G.arcs[i][j].weight==M){
SetTextC6;
cout<<"\t"<<"";
SetTextC5;
}else{
cout<<"\t<"<";
}
}
cout<}
SetTextC1;
}
}
boolGraphics:
:
Mark_FindMaxstream(Graphics&G){
inti,j,k,x;
doubledis;
boolboolean=false;
//step1找到vs,并对与其相连的顶点标记
i=G.LocateIndex(G,"vs");//找到顶点vs
G.vexs[i].flowsDiff=M;
G.vexs[i].mark=h_marked;
boolean=G.Mark_Node(G,i);//标记顶点
if(!
boolean){
cout<<"没有找到增广链"<returnfalse;
}
//step2从标记的点中找已标记未检查的点
i=0;
j=0;
while(G.vexs[i]pare("vt")!
=0&&G.vexs[i].mark!
=n_mark){//当vt找到且有标记时停止
if(G.vexs[i].mark==marking){
x=0;
G.vexs[i].mark=h_marked;//代表已经检查
G.Mark_Node(G,i);//标记从当前点出发的未标记的点
k=G.CheckMarkNode(G,i);//检查:
已标记未检查的点进行h_marked标记并返回i
if(k==i){
//cout<<"k==i出错"<for(j=0;jif(G.vexs[j].mark==marking){
x=x+1;
break;
}
}
if(x==1){
i=x;
}else{
cout<<"k==i出错"<returnfalse;
}
}else{
i=k;
}
}
if(j==G.vexnum){//找完所有点也不满足条件时停止
i=i+1;
}
j++;
}
//step3路径值调整
i=G.LocateIndex(G,"vt");
dis=G.vexs[i].flowsDiff;//得到vt的流量差
stringforvex;
stringforvex1;
while(G.vexs[i]pare("vs")!
=0){//当顶点为vs时停止
forvex=G.vexs[i].formerVex;
if(forvex.substr(0,1).compare("-")==0){
forvex1=forvex.substr(1,2);
j=G.LocateIndex(G,forvex1);
G.arcs[i][j].flows=G.arcs[i][j].flows-dis;//反向,流量减
}else{
j=G.LocateIndex(G,forvex);//得到前面的顶点的下标
G.arcs[j][i].flows=G.arcs[j][i].flows+dis;//正向,流量加
}
i=j;
}
returntrue;
}
boolGraphics:
:
Mark_Node(Graphics&G,inti){
intj;
doublea,b;
boolb1=false,b2=false;
for(j=0;jif(G.vexs[j].mark==n_mark){
if(G.arcs[i][j].weight!
=M){//判断是否相连
if(G.arcs[i][j].flows!
=G.arcs[i][j].weight){//正向不是饱和流,标记
G.vexs[j].mark=marking;
G.vexs[j].formerVex=G.vexs[i].vexs;
a=G.vexs[i].flowsDiff;
b=G.arcs[i][j].weight-G.arcs[i][j].flows;
G.vexs[j].flowsDiff=bb:
a;
b1=true;
}
}
if(G.arcs[j][i].weight!
=M){//判断反向相连
if(G.arcs[j][i].flows!
=0){//判断是否零流,标记
G.vexs[j].mark=marking;
G.vexs[j].formerVex="-"+G.vexs[i].vexs;
a=G.vexs[i].flowsDiff;
b=G.arcs[j][i].flows;
G.vexs[j].flowsDiff=bb:
a;
b2=true;
}
}
}
}
returnb1||b2;
}
intGraphics:
:
CheckMarkNode(Graphics&G,inti){
intj=0;
for(j=0;jif(G.arcs[i][j].weight!
=M){//判断是否相连
if(G.vexs[j].mark==marking){//相连,且为marking
returnj;
}
}
if(G.arcs[j][i].weight!
=M){//判断反向相连
if(G.vexs[j].mark==marking){//相连,且为marking
returnj;
}
}
}
returni;
}
intmain(){
GraphicsG;
SetTextC7;
cout<<"//标号寻找最大流算法"<cout<<"//顶点从vs开始"<cout<<"//可以求出vs到vt的一条流量最大的路"<cout<<"//其中M表示的无穷大"<SetTextC1;
G.Mark_getMaxstream(G);
return0;
}