|
<>//2005.4.12 <BR>//written by shenhui<BR>//此算法必须指定要求的最大流stream,如果结果无限循环的出现<BR>//一些字或者什么也不出现,则说明该图达不到此流量。<BR>#include "iostream.h" <BR>#define max 10000<BR>#define n 5 //根据不同问题可修改大小<BR>#define stream 10 //根据不同问题可修改<BR> <BR> <BR>//最大容量矩阵<BR>int c[n][n]={{0,10,8,max,max},{max,0,max,2,7},{max,5,0,10,max},{max,max,max,0,4},{max,max,max,max,0}};<BR>//实际流量矩阵<BR>int flow[n][n]={{0,0,0,max,max},{max,0,max,0,0},{max,0,0,0,max},{max,max,max,0,0},{max,max,max,max,0}};<BR>//费用矩阵<BR>int money[n][n]={{0,4,1,max,max},{max,0,max,6,1},{max,2,0,3,max},{max,max,max,0,2},{max,max,max,max,0}};<BR>//增广链向量<BR>int p[n]={0,0,0,0,0}; //原点到各点的最短路径<BR>int D[n]; //原点到各点的路长(用于Dijkstra法中)<BR>int pt[n]={0,0,0,0,0}; //原点到各点的路长(用于逐次逼近法中)</P>
<>int maxflow; //设置最大流量</P>
<><BR>//----------------------------计算Vs--Vt最短路径模块---------------------------------------------//</P>
<P>void Dijkstra() //求源点V0到其余顶点的最短路径及其长度;得到一条增广链<BR>{<BR> int s[n]; //D[n]最后保存各点的最短路径长度<BR> int i,j,k,vl,pre; <BR> int min;<BR> int inf=20000;<BR> vl=0; //求V0到Vn的增广链<BR> for(i=0;i<n;i++)<BR> { <BR> D=money[vl]; //置初始距离值 <BR> if((D!=max) && (D!=0)) p=1;<BR> else p=0;<BR> }</P>
<P> for(i=0;i<n;i++) s=0; <BR> s[vl]=1; D[vl]=0;<BR> for(i=0;i<n;i++)<BR> {<BR> min=inf;<BR> for(j=0;j<n;j++)<BR> if((!s[j]) && (D[j]<min))<BR> {<BR> min=D[j];<BR> k=j;<BR> }<BR> s[k]=1;<BR> if(min==max) break;<BR> for(j=0;j<n;j++)<BR> if((!s[j]) && (D[j]>D[k]+money[k][j]))<BR> {<BR> D[j]=D[k]+money[k][j];<BR> p[j]=k+1;<BR> }<BR> } //此时所有顶点都已扩充到红点集S中<BR> <BR> <BR> cout<<"Vs到Vt的最短路径为(长和径):\n";<BR> for(i=0;i<n;i++)<BR> {<BR> if(i=n-1){<BR> cout<<D<<" "<<i+1; //这里不需要打印<BR> pre=p;<BR> while (pre!=0)<BR> {<BR> cout<<"<-- "<<pre; //这里不需要打印<BR> pre=p[pre-1]; //p[]中保存的路径的顶点标号从1开始,不是0;<BR> }<BR> cout<<"\n";}<BR> }<BR>} <BR>//-----------------------------------END Dijkstra()-----------------------------------------//</P>
<P><BR>//------------------用最大流算法的方法调整实际流量矩阵flow[][],以扩充其流量----------------//<BR>void modify() <BR>{<BR> int i,min;<BR> int pre;<BR> if(D[n-1]==max) <BR> {<BR> cout<<"不存在增广链";<BR> return;<BR> }</P>
<P> pre=p[n-1];<BR> i=n-1;<BR> min=c[pre-1]-flow[pre-1]; //增广路上的最后一条边的长<BR> while(pre!=0) //再增广路上算出所能增加流量的最大值<BR> {<BR> i=pre-1;<BR> pre=p[pre-1];<BR> if(min>c[pre-1]-flow[pre-1])<BR> min=c[pre-1]-flow[pre-1];<BR> if(pre==1)<BR> pre=0;<BR> }<BR> if((min+maxflow)>stream)<BR> min=stream-maxflow;<BR> pre=p[n-1]; //在增广链上添加流量<BR> i=n-1;<BR> flow[pre-1]+=min;<BR> while(pre!=0)<BR> {<BR> i=pre-1;<BR> pre=p[pre-1];<BR> flow[pre-1]+=min;<BR> if(pre==1)<BR> pre=0;<BR> }<BR>}<BR>//----------------------------------END modify()----------------------------------//</P>
<P><BR>//--------------------------------调整费用矩阵money[][]-----------------------------//<BR>void modifymoney() <BR>{<BR> int i,j;<BR> int moneypre[n][n];<BR> for(i=0;i<n;i++)<BR> for(j=0;j<n;j++)<BR> moneypre[j]=money[j];<BR> for(i=0;i<n;i++)<BR> for(j=0;j<n;j++)<BR> {<BR> if(i<j){<BR> if(c[j]!=max && c[j]>flow[j])<BR> money[j]=moneypre[j];<BR> if((c[j]!=max && c[j]==flow[j]) || (c[j]==max && flow[j]==max))<BR> money[j]=max;}<BR> if(i>j){<BR> if( flow[j]>0 )<BR> money[j]=-moneypre[j];<BR> if(flow[j]==0)<BR> money[j]=max;}<BR> }<BR> for(i=0;i<n;i++)<BR> for(j=0;j<n;j++)<BR> {<BR> if(i==j)<BR> money[j]=0;<BR> if(money[j]==-max)<BR> money[j]=max;<BR> }<BR>}<BR>//----------------------------------END modifymoney()----------------------------------//</P>
<P>//----------------------------采用逐次逼近法得到一条增广链----------------------------//<BR>void approach() <BR>{<BR> int pf[n],ptf[n]={0,0,0,0,0}; //当N变动时,0的个数应与N一致<BR> int min=max;<BR> int i,j,flag;<BR> for(j=0;j<n;j++)<BR> pt[j]=money[0][j]; //直接距离做初始解<BR> do{<BR> flag=1;<BR> for(j=0;j<n;j++) <BR> pf[j]=pt[j]; //将上一次得到的路径迭代结果保存入pf[]<BR> for(i=0;i<n;i++)<BR> {<BR> min=pt;<BR> for(j=0;j<n;j++)<BR> {<BR> <BR> if(min>(pt[j]+money[j]))<BR> min=pt[j]+money[j];<BR> }<BR> ptf=min;<BR> }<BR> <BR> for(i=0;i<n;i++)<BR> { <BR> pt=ptf;<BR> if(pf!=pt)<BR> flag=0; //两次迭代的值不同,继续<BR> }<BR> }while(flag==0);</P>
<P> j=n-1; <BR> for(i=0;i<j;i++) //找出最短路径走向<BR> if(pt+money[j]==pt[j])<BR> {<BR> p[j]=i+1; //p[j]中的下标从1开始<BR> if(p[j]==1) break; <BR> j=i;<BR> i=-1;<BR> <BR> <BR> } <BR> for(i=0;i<n;i++) <BR> D=pt;<BR>}<BR>//------------------------------END approach()------------------------------//</P>
<P><BR>void main()<BR>{<BR> int i,j;<BR> Dijkstra();<BR> <BR> while( 1 ) <BR> { <BR> modify(); //调整流量矩阵<BR> maxflow=0;<BR> for(j=0;j<n;j++)<BR> {<BR> if(flow[0][j]!=max)<BR> maxflow+=flow[0][j];<BR> }<BR> if(maxflow==stream) break; <BR> modifymoney();<BR> approach(); //采用逐次逼近法得到一条增广链 <BR> <BR> <BR> <BR> }<BR> <BR> <BR> cout<<"流量矩阵:\n";<BR> for(i=0;i<n;i++) //<BR> {<BR> for(j=0;j<n;j++)<BR> cout<<flow[j]<<" ";<BR> cout<<"\n";<BR> }<BR> <BR> cout<<"费用矩阵:\n";<BR> for(i=0;i<n;i++) //<BR> {<BR> for(j=0;j<n;j++)<BR> cout<<money[j]<<" ";<BR> cout<<"\n";<BR> }<BR>}</P> |
|