最小费用最大流问题叠加算法
例:求解图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 。