[图论]最小费用最大流问题-叠加算法C语言实现

最小费用最大流问题叠加算法

例:求解图1到流量依次为28的最小费用流;并求解其最小费用最大流。弧旁数字为(其中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 。


  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值