1. 程式人生 > >最小費用最大流

最小費用最大流

dinic min man 多個 轉化 pan 多少 最短路 +=

一、問題描述

最小費用最大流: 在最大流有多組解時,給每條邊在附上一個單位費用的量,問在滿足最大流時的最小費用是多少?

二、算法描述

思想: 給出一個容量網絡,那他的最大流一定是一個定值(即使是有多個一樣的最大值)。所以我們從開始的可行流開始增廣時,最終的增廣量是一定的。所以為了滿足最小費用我們只需要每次找最小費用的增廣路即可,直到流量為最大值。這個問題僅僅是在求增廣路時先考慮費用最小的增廣路,其他思想和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; 
} 

  

最小費用最大流