最小費用最大流問題

來源:互聯網
上載者:User

基於網路最大流問題,進一步提出的最小費用問題,費用權值和最大流問題的容量限制是兩個概念,實質上這個問題就是求圖的加權最短路,只是要在最大流的前提下實現。所以要用Bellman-Ford演算法找增廣路的同時計算最小費。
下面是紫書中求最小費最大流的模板`

const int maxn = 2000 + 10;const int INF = 1000000000;struct Edge {  int from, to, cap, flow, cost;  Edge(int u, int v, int c, int f, int w):from(u),to(v),cap(c),flow(f),cost(w) {}};struct MCMF {  int n, m;  vector<Edge> edges;  vector<int> G[maxn];  int inq[maxn];         // 是否在隊列中  int d[maxn];           // Bellman-Ford  int p[maxn];           // 上一條弧  int a[maxn];           // 可改進量  void init(int n) {    this->n = n;    for(int i = 0; i < n; i++) G[i].clear();    edges.clear();  }  void AddEdge(int from, int to, int cap, int cost) {    edges.push_back(Edge(from, to, cap, 0, cost));    edges.push_back(Edge(to, from, 0, 0, -cost));    m = edges.size();    G[from].push_back(m-2);    G[to].push_back(m-1);  }  bool BellmanFord(int s, int t, int flow_limit, int& flow, int& cost) {    for(int i = 0; i < n; i++) d[i] = INF;    memset(inq, 0, sizeof(inq));    d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;    queue<int> Q;    Q.push(s);    while(!Q.empty()) {      int u = Q.front(); Q.pop();      inq[u] = 0;      for(int i = 0; i < G[u].size(); i++) {        Edge& e = edges[G[u][i]];        if(e.cap > e.flow && d[e.to] > d[u] + e.cost) {          d[e.to] = d[u] + e.cost;          p[e.to] = G[u][i];          a[e.to] = min(a[u], e.cap - e.flow);          if(!inq[e.to]) { Q.push(e.to); inq[e.to] = 1; }        }      }    }    if(d[t] == INF) return false;    flow += a[t];    cost += d[t] * a[t];    for(int u = t; u != s; u = edges[p[u]].from) {      edges[p[u]].flow += a[t];      edges[p[u]^1].flow -= a[t];    }    return true;  }  // 需要保證初始網路中沒有負權圈  int MincostFlow(int s, int t, int flow_limit, int& cost) {    int flow = 0; cost = 0;    while(flow < flow_limit && BellmanFord(s, t, flow_limit, flow, cost));    return flow;  }};

還有一道題目
Admiral UVA - 1658



使用的是拆點法:把2~v-1的每個點都拆成i和i’兩個,然後i和i’間連一個容量1,費用為0的邊,最後限制最大流為2時的最小費用即可。

拆解的辦法:對點2~n-1拆成弧i->i’,前者(節點)編號為1~n-2,後者編號為n~2n-3
for(int i = 2; i <= n-1; i++)
T.AddEdge(i-1, i+n-2, 1, 0);
對於 flow += a[t]的a[t]要做個限幅,最大流量不能超過2要保證計算出的最小費用是在流量為2的前提下
while(flow < flow_limit && BellmanFord(s, t, flow_limit, flow, cost));
完整代碼如下:

// UVA1658.cpp : 定義控制台應用程式的進入點。//#include <iostream>#include <algorithm>#include <queue>#include <string.h>using namespace std;#define INF 1000000000const int maxn = 2005;struct Edge{    int from, to, cap, flow, cost;//起點,終點,容量,流量,花費    Edge(int u, int v, int c, int f, int w) :from(u), to(v), cap(c), flow(f), cost(w)    {    }//建構函式};struct mincmaxf{    int n, m;//n表示結點數目,m表示邊的數目    vector<Edge>edges;    vector<int>G[maxn];    int inq[maxn];//標記是否在隊列中    int d[maxn];//費用記錄,即是bellman-ford演算法中的最短路    int p[maxn];//指向父邊,上一條邊,為了找完一條通路後進行增廣    int delta[maxn];//記錄殘留網路值    void init(int n){        this->n = n;        for (int i = 0; i < n; i++)            G[i].clear();        edges.clear();    }    void AddEdge(int from, int to, int cap,int cost){        edges.push_back(Edge(from, to, cap, 0, cost));        edges.push_back(Edge(to, from, 0, 0, -cost));        m = edges.size();        G[from].push_back(m - 2);        G[to].push_back(m - 1);    }    bool BellmanFord(int s, int t, int flow_limit, int &flow, long long &cost)    {        for (int i = 0; i < n; i++)            d[i] = INF;        memset(inq, 0, sizeof(inq));        d[s] = 0; inq[s] = 1; p[s] = 0; delta[s] = INF;        queue<int>Q;        Q.push(s);        while (!Q.empty()){            int u = Q.front(); Q.pop();            inq[u] = 0;//代表u出隊了            for (int i = 0; i<G[u].size(); i++)            {                Edge &e = edges[G[u][i]];                if (e.cap>e.flow&&d[e.to] > d[e.from] + e.cost)                {                    d[e.to] = d[u] + e.cost;//更新最小花費                    p[e.to] = G[u][i];                    delta[e.to] = min(delta[u], e.cap - e.flow);//更新殘留網路值                    if (!inq[e.to]){//防止回溯搜尋時再次搜到已經搜尋過的邊                        Q.push(e.to);                        inq[e.to] = 1;                    }                }            }        }        if (d[t] == INF)return false;        //這句在本題中可要可不要,要了更嚴謹一些        //if (flow + delta[t] > flow_limit) delta[t] = flow_limit - flow;        flow += delta[t];        cost += (long long)d[t] * (long long) delta[t];//求出當前費用        for (int u = t; u != s; u = edges[p[u]].from)//回溯        {            edges[p[u]].flow += delta[t];            edges[p[u]^1].flow -= delta[t];        }        return true;    }    int MincostMaxFlow(int s, int t, int flow_limit,long long &cost)    {        int flow = 0;        cost = 0;        while (BellmanFord(s, t, flow_limit, flow, cost)&&flow <flow_limit);        return flow;    }};int main(){    int n=0, m = 0;    mincmaxf T;    int div[1005];    while (cin >> n >> m &&n>0)    {        int a1, a2, a3;        int temp = n;        long long mincost;        memset(div, 0, sizeof(div));        T.init(n*2-2);        for (int i = 2; i <= n - 1; i++)            T.AddEdge(i - 1, i + n - 2, 1, 0);        for (int i = 0; i < m; i++)        {               cin >> a1>>a2 >> a3;                    if (a1 != 1 && a1 != n) a1 += n - 2;             else a1--;            a2--;            T.AddEdge(a1, a2, 1, a3);        }        T.MincostMaxFlow(0, n-1, 2,mincost);        cout << mincost << endl;    }    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.