最小费用最大流

一、问题描述

最小费用最大流:  在最大流有多组解时,给每条边在附上一个单位费用的量,问在满足最大流时的最小费用是多少?

二、算法描述

思想:  给出一个容量网络,那他的最大流一定是一个定值(即使是有多个一样的最大值)。所以我们从开始的可行流开始增广时,最终的增广量是一定的。所以为了满足最小费用我们只需要每次找最小费用的增广路即可,直到流量为最大值。这个问题仅仅是在求增广路时先考虑费用最小的增广路,其他思想和EK思想一样。  

我们学过SPFA求最短路算法(bellman-ford的队列优化),所以我们将弧的费用看做是路径长度,即可转化为求最短路的问题了。只需要所走的最短路满足两个条件即可:1可增广cap> flow,2路径变短d[v]>d[u]+cost< u,v> 。  

关于建图的方式和Dinic,ISAP算法一样,如有疑问可以去我们其他相关博客看看。

模板:

//最小费用最大流,求最大费用只需要取相反数,结果取相反数即可。 
//点的总数为 N,点的编号 0~N-1 
const int MAXN = 10000; 
const int MAXM = 100000; 
const int INF = 0x3f3f3f3f; 
struct Edge 
{ 
    int to,next,cap,flow,cost; 
}edge[MAXM]; 
int head[MAXN],tol; 
int pre[MAXN],dis[MAXN]; 
bool vis[MAXN]; 
int N;//节点总个数,节点编号从0~N-1 
void init(int n) 
{ 
    N = n; 
    tol = 0; 
    memset(head,-1,sizeof(head)); 
} 
void addedge(int u,int v,int cap,int cost) 
{ 
    edge[tol].to = v; 
    edge[tol].cap = cap; 
    edge[tol].cost = cost; 
    edge[tol].flow = 0; 
    edge[tol].next = head[u]; 
    head[u] = tol++; 
    edge[tol].to = u; 
    edge[tol].cap = 0; 
    edge[tol].cost = -cost; 
    edge[tol].flow = 0; 
    edge[tol].next = head[v]; 
    head[v] = tol++; 
} 
bool spfa(int s,int t) 
{ 
    queue<int>q; 
    for(int i = 0;i < N;i++) 
    { 
        dis[i] = INF; 
        vis[i] = false; 
        pre[i] = -1; 
    } 
    dis[s] = 0; 
    vis[s] = true; 
    q.push(s); 
    while(!q.empty()) 
    { 
        int u = q.front(); 
        q.pop(); 
        vis[u] = false; 
        for(int i = head[u]; i != -1;i = edge[i].next) 
        { 
            int v = edge[i].to; 
            if(edge[i].cap > edge[i].flow && 
               dis[v] > dis[u] + edge[i].cost ) 
            { 
                dis[v] = dis[u] + edge[i].cost; 
                pre[v] = i; 
                if(!vis[v]) 
                { 
                    vis[v] = true; 
                    q.push(v); 
                } 
            } 
        } 
    } 
    if(pre[t] == -1)return false; 
    else return true; 
} 
//返回的是最大流,cost存的是最小费用 
int minCostMaxflow(int s,int t,int &cost) 
{ 
    int flow = 0; 
    cost = 0; 
    while(spfa(s,t)) 
    { 
        int Min = INF; 
        for(int i = pre[t];i != -1;i = pre[edge[i^1].to]) 
        { 
            if(Min > edge[i].cap - edge[i].flow) 
                Min = edge[i].cap - edge[i].flow; 
        } 
        for(int i = pre[t];i != -1;i = pre[edge[i^1].to]) 
        { 
            edge[i].flow += Min; 
            edge[i^1].flow -= Min; 
            cost += edge[i].cost * Min; 
        } 
        flow += Min; 
    } 
    return flow; 
} 

  

原文地址:https://www.cnblogs.com/xzxl/p/7236170.html