最小费用最大流算法(SPFA邻接矩阵)

/* 
  Name: 最小费用最大流算法(SPFA邻接矩阵) 
  Copyright:  
  Author: 巧若拙  
  Date: 16-06-17 22:08 
  Description: 每次以单位费用为权值,寻找src到des的最短增广路路径,然后对该路径进行增量修改,
  先计算出最小增量,然后累计最小费用值,同时更新残流网络和费用网络。
  再次用SPFA算法寻找src到des的最短增广路路径,直到找不到增广路径,算法结束。 
*/  
  
#include<iostream>    
#include <fstream>  
    
using namespace std;    
    
const int MAXV=2000;   //最大顶点数量     
const int MAXE=2000;   //最大边数量    
const int INFINITY = 0x7fffffff;   //无穷大     
int capacity[MAXV][MAXV]; //记录残流网络的容量    
int cost[MAXV][MAXV]; //记录网络的费用    
int pre[MAXV];  //标记在这条路径上当前节点的前驱
    
int MinCostMaxFlow(int src, int des, int n)  ;    
bool SPFA(int src, int des, int n);//寻找src到des的最短路径(以单位费用为权值),若不存在增广路,则返回false     
    
int main()    
{   
    int  m, n, u, v;    
    ifstream fcin("mcmf.txt");  
      
    if (!fcin.is_open())  
    {  
        cout << "Error opening file"; exit (1);  
    }  
    
    fcin >> n >> m;  
     
    for(int i=0; i<m; ++i)    
    {    
        fcin >> u >> v;    
        fcin >> capacity[u][v] >> cost[u][v];   
    }    
      
    cout << n << " " << m << endl;  
    for (int i=0; i<n; i++)  
    {  
        for (int j=0; j<n; j++)  
        {  
            cout << "(" << capacity[i][j] << "," << cost[i][j] << ") ";  
        }  
        cout << endl;  
    }  
        
    cout << MinCostMaxFlow(0, n-1, n) << endl;    
    
    system("pause");                       
    return 0;    
}    
    
int MinCostMaxFlow(int src, int des, int n)    
{    
    int sumCost = 0; //存储 src到des的最大流最小费用  
    int u, v, inc, tempCost;    
    
    for (int i=0; i<n; i++) //初始化费用网络 
    {
        for (int j=0; j<n; j++)
        {
            if (cost[i][j] == 0)
            {
                cost[i][j] = INFINITY;
            }
        }
        cost[i][i] = 0;
    }
      
    while (SPFA(src, des, n))    
    {    
        inc = INFINITY;
        for (v=des,u=pre[v]; u!=-1; v=u,u=pre[v]) //计算增广路的最小增量 
        {
            inc = (inc < capacity[u][v]) ? inc : capacity[u][v]; cout << v << "->";  
        } cout << endl; 
        
        for (v=des,u=pre[v]; u!=-1; v=u,u=pre[v]) //更新残流网络和费用网络 
        {
            sumCost += cost[u][v] * inc;  cout << sumCost << "+=" << cost[u][v] << "*" << inc << endl;
            capacity[u][v] -= inc;    
            capacity[v][u] += inc; 
            
            cost[v][u] = (capacity[v][u] > 0) ? -cost[u][v] : INFINITY; 
            cost[u][v] = (capacity[u][v] > 0) ? cost[u][v] : INFINITY; //注意:cost[u][v]的值可能发生了变化,故不能和上一行交换顺序 
        }
    } 
    
    return sumCost;    
}    
  
bool SPFA(int src, int des, int n)//寻找src到des的最短路径(以单位费用为权值),若不存在增广路,则返回false    
{    
    int Queue[MAXV] = {0};   //求最短增广路算法需要用到的队列     
    int InQueue[MAXV] = {0}; //标记顶点是否在队列中 
    int dis[MAXV] = {0};   //存储src到顶点的最短路径
    int u, front = 0, rear = 0; //清空队列     
        
    for(int i=0; i<n; ++i) //初始化列表     
    {    
        pre[i] = -1; 
        dis[i] = INFINITY;   
    }    
    
    //源点加入队列 
    dis[src] = 0;
    Queue[rear++] = src;  
    InQueue[src] = 1;    
        
    while (front < rear) //队列非空    
    {    
        u = Queue[front++];   
        for (int i=0; i<n; ++i) //寻找未访问过的邻接点,并设置层数    
        {    
            if (cost[u][i] != INFINITY && dis[i] > dis[u] + cost[u][i])     
            {    
                dis[i] = dis[u] + cost[u][i];
                pre[i] = u;
                  
                if (InQueue[i] == 0) //顶点不在队列中,则入列 
                {    
                    Queue[rear++] = i;    
                    InQueue[i] = 1;  
                }    
            }    
        }   
        
        InQueue[u] = 0; //顶点u出列 
    }    
        
    return (pre[des] != -1);    
}    

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值