最小费用最大流问题叠加算法
例:求解图1的到流量依次为2、8的最小费用流;并求解其最小费用最大流。弧旁数字为(其中b为单位费用函数,c为容量函数,下同);
图1
给出一种算法求解最小费用最大流问题。
下面给出该算法的C语言实现。
#include<stdio.h>
int matrix[100][100],b[100][100],b_bf[100][100],st[100][100]={0};//matrix为容量矩阵 ,b为费用矩阵
int distance[100][100]={0};
int n,i,j,ini,tre,kkk,sum=0;//ini为初始下标 ,tre终点
char temp[100];
int flag_exit=1,flag_no=0;//exit用于判断是否跳出,exit用于判断是否有k的可行流!
void inputmatrix()
{
printf("请输入邻接矩阵的阶数:\n");
scanf("%d",&n);
printf("请输入有向图的容量矩阵:\n");
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
scanf("%d",&matrix[i][j]);
}
printf("请输入有向图的费用矩阵:\n");
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{scanf("%d",&b[i][j]);
b_bf[i][j]=b[i][j];//备份数据!
}
}
printf("请输入流量值:(输入0代表求解的问题是最小费用最大流问题!)\n");
scanf("%d",&kkk);
printf("请输入需计算的起始点下标:\n");
scanf("%d",&ini);
printf("请输入需计算的终点下标:\n");
scanf("%d",&tre);
}
void caculate(int n,int a[100][100],int ini,int tre)//a为费用矩阵,b为可行流矩阵
{
int k,t=0,t1,t2,min,j,w,flag=0;/*k,k1作为循环的次数,flag=1意味着可以继续循环,flag=0,跳出*/
int path[100][100] = {0};//初试为空,记录path
for(i=0;i<n;i++)
for(j=0;j<n;j++)
path[i][j] = -1;
path[ini-1][0]=ini-1;
distance[0][ini-1]=0;
for(i=0;i<n;i++)
if(i!=ini-1)
distance[0][i]=10000000;//初始化值,代表无穷大
for(k=1;k<n;k++)
{
int flag=1;
for(j=0;j<n;j++)
distance[k][j]=distance[k-1][j];//for 任意u<V,do 这个
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
if(a[i][j]!=0&&i!=j&&(distance[k-1][i]+a[i][j])<distance[k][j]) /*寻找符合条件的数*/
{
flag=0;//有更新,继续循环,无更新操作,跳出
t1=j;
t2=i;
distance[k][j]=distance[k-1][i]+a[i][j];
//保存路径
for(w=0;w<n;w++)//把t2的值加给t1,并且最后加上t1该点
{
if(path[t2][w]!=-1)
path[t1][w]=path[t2][w];
else
{
path[t1][w]=t1;
break;
}
}
}
}
if(flag)
break;
} //改变费用矩阵,并增广
if(path[tre-1][0]==-1)
{
flag_exit=0;//无最短路,可跳出!
if(kkk>sum)
{printf("\n\n-----不存在费用为%d的可行流!-----\n\n\n",kkk);
flag_no=1;}}
if(flag_exit)
{min=matrix[path[tre-1][0]][path[tre-1][1]]-st[path[tre-1][0]][path[tre-1][1]];//剩余值,下求最小进行增广
for(j=0;j<n-1;j++)
{ //判断并求可增广的最小值!
if((matrix[path[tre-1][j]][path[tre-1][j+1]]-st[path[tre-1][j]][path[tre-1][j+1]])>0
&&path[tre-1][j+1]!=-1&&min>(matrix[path[tre-1][j]][path[tre-1][j+1]]-st[path[tre-1][j]][path[tre-1][j+1]]))
min=matrix[path[tre-1][j]][path[tre-1][j+1]]-st[path[tre-1][j]][path[tre-1][j+1]];
else if(path[tre-1][j+1]==-1)
break;
}
if(kkk<(sum+min)&&kkk!=0)
{
min=kkk-sum;//只需要增广达到k就可以
flag_exit=0;//可跳出!
}
sum+=min;
for(j=0;j<n-1;j++)//min为求得的最小值,下面增广并求出剩余网络矩阵!
if(path[tre-1][j+1]!=-1)
{
if(b[path[tre-1][j]][path[tre-1][j+1]]>0)
st[path[tre-1][j]][path[tre-1][j+1]]+=min;//进行增广计算
else if(b[path[tre-1][j]][path[tre-1][j+1]]<0)
st[path[tre-1][j+1]][path[tre-1][j]]-=min;//进行增广计算
if(st[path[tre-1][j]][path[tre-1][j+1]]!=0&&st[path[tre-1][j]][path[tre-1][j+1]]<matrix[path[tre-1][j]][path[tre-1][j+1]])
{
b[path[tre-1][j+1]][path[tre-1][j]]=-b_bf[path[tre-1][j]][path[tre-1][j+1]];//改变费用矩阵
b[path[tre-1][j]][path[tre-1][j+1]]=b_bf[path[tre-1][j]][path[tre-1][j+1]];
}
else if(st[path[tre-1][j]][path[tre-1][j+1]]==matrix[path[tre-1][j]][path[tre-1][j+1]]){
b[path[tre-1][j]][path[tre-1][j+1]]=0;//改变费用矩阵
b[path[tre-1][j+1]][path[tre-1][j]]=-b_bf[path[tre-1][j]][path[tre-1][j+1]];
}
else if(st[path[tre-1][j]][path[tre-1][j+1]]==0)
{
b[path[tre-1][j]][path[tre-1][j+1]]=b_bf[path[tre-1][j]][path[tre-1][j+1]];
}
} } }
main()
{
inputmatrix(); //调用输入函数
while(flag_exit)
caculate(n,b,ini,tre); //一直调用bellman_ford算法进行求解,直至找不到最短路!
if(flag_no==0){//输出最终结果!
if(kkk!=0)printf("\n\n---------得到流量为%d最小费用流的矩阵形式如下----------\n\n",kkk);
else printf("\n\n---------得到最小费用最大流的矩阵形式如下----------\n\n");
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
printf("%d ",st[i][j]);
}
printf("\n");
} }
system("pause");
}
下面给出运行结果针对图1 。