图论: 最小费用最大流

                                                                                                            最小费用最大流问题
问题描述:
                        在最大流的问题上面, 加上了费用: 假设每条边除了有一个流量的限制外 , 还有一个单位流量的费用.
                  即: 给出最大流量的前提下, 还要附加上最小费用. 这就是最小费用最大流问题.
问题解析:
                              在此问题下, 你会发想平行边变得有意义了 , 可能会从u到v的弧 , 费用分别会是w1,w2 . 之前我们是
          可以将它们合并的. 现在我们无法将它们合并了. 为什么? 因为若e(u,v) , e(v,u)同时存在, 且费用都是负数
          代表: 从u流向v的 和 从v流向u的. 这个问题我们可以通过临接表巧妙的解决.
                另外我们规定: cost(u,v) + cost(v,u) = 0. 代表反向增广时是减小费用.
  实现方法:
                spfa算法 + 临接表
                spfa算法 + 临接矩阵
代码:
临接表:
bool spfa(int start,int end)
{
 

   int dist[MAX];
    queue<int> qu;
    
    p[start] = -1;
    qu.push(start);
    vis[start] = true;
    
    
    for(int i = 0; i <= n+2; ++i)
    {
        dist[i] = (i == start ? 0 : INF);
    }
    
    while( !qu.empty() )
    {
        int k = qu.front();
        qu.pop();
        vis[k] = false;
        
        for(int e = first[k]; e != -1; e = edges[e].next)
        {
            if(edges[e].f > 0 && dist[edges[e].v] > dist[k] + edges[e].w)
            {
                dist[edges[e].v] = dist[k] + edges[e].w;
                p[edges[e].v] = e;
                if(!vis[edges[e].v])
                {
                    vis[edges[e].v] = true;
                    qu.push(edges[e].v);
                }
            }
        }
    }
    
    if(dist[end] < INF)
        return true;
    else
        return false;
    
}

int result()
{
    int minflow = INF;
    for(int i = p[n+1]; i != -1; i = p[edges[i].u])
    {
        if(minflow > edges[i].f)
            minflow = edges[i].f;
    }
    
    for(int i = p[n+1]; i != -1; i = p[edges[i].u])
    {
        edges[i].f -= minflow;
        edges[i^1].f += minflow;
        mincost += edges[i].w * minflow;
    }
}





临接矩阵 :
bool spfa()
{

   queue<int> qu;
    memset(vis,false,sizeof(vis));
    memset(p,-1,sizeof(p));
    for(int i = 1; i <= num_man+num_house+1; ++i)
        dist[i] = (i == start ? 0 : INF);
    vis[start] = true;
    qu.push(start);
    
    while( !qu.empty() )
    {
        int u = qu.front();
        qu.pop();
        vis[u] = false;
        
        for(int v = 1; v <= num_man+num_house+1; ++v)
        {
            if(cap[u][v] > flow[u][v] && dist[v] > dist[u] + cost[u][v])
            {
                dist[v] = dist[u] + cost[u][v];
                p[v] = u;
                if( !vis[v] )
                {
                    vis[v] = true;
                    qu.push(v);
                }
            }
        }
    }
    if(dist[end] >= INF)
        return false;
    else
        return true;
    
}

void solve()
{
    int minflow;
    while(true)
    {
        if(!spfa())
            break;
        minflow = INF;
        for(int u = end; u != start; u = p[u])
        {
            minflow = min(minflow,cap[p[u]][u] - flow[p[u]][u]);
        }
        for(int u = end; u != start; u = p[u])
        {
            flow[p[u]][u] += minflow;
            flow[u][p[u]] -= minflow;
            
        }
        result += dist[end]*minflow;
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值