zoukankan      html  css  js  c++  java
  • 最小费用最大流

      在这里学会的最小费用最大流问题。

    定义:图G以S为源点,T为汇点。c(i, j)为G的容量,f(i, j)为G的流,w(i, j)为单位流量的费用且w(i, j) = -w(j, i)。费用wf = ∑(fij * wij)  (i, j)∈E(G)。就是求最大流F的情况下保证wf最小。

      思想:利用Ford-Fulkerson算法的思想,不断的在残留网络中找增广路,这里找的增广路是当前网络从S到T的以单位流量为权值的最短了。因为涉及道负权,所以可以选择spfa或者

    bellman-ford。

    实现代码:

    const int N = 110;
    const int M = N*N*2;
    
    int n, m, k;
    int b[N], sumb;
    int c[N][N];
    int S, T;
    
    struct node {
        int from, to, cost, flow, next;   //
    } g[M];
    
    int head[N], t;
    
    void init() {
        CL(head, -1); t = 0;
    }
    
    void add(int u, int v, int f, int w) {
        g[t].from = u; g[t].to = v;  g[t].cost = w; g[t].flow = f;
        g[t].next = head[u]; head[u] = t++;
    
        g[t].from = v; g[t].to = u; g[t].cost = -w; g[t].flow = 0;
        g[t].next = head[v]; head[v] = t++;
    }
    
    void build() {
        init();
        int i, j;
        S = 0; T = m + n + 1;
    
        for(i = 1; i <= n; ++i) {
            add(S, i, 1, 0);    //flow, cost;
        }
        for(i = 1; i<= m; ++i) {
            for(j = 1; j <= n; ++j) {
                if(c[i][j]) add(j, i + n, 1, 0);
            }
        }
        for(j = 1; j <= m; ++j) {
            add(j+n, T, b[j]/k, k);
            if(b[j]%k > 1) {
                add(j + n, T, 1, b[j]%k);
            }
        }
    }
    
    int dis[N];
    int pre[N];
    bool vis[N];
    queue<int> q;
    
    bool spfa() {    //找最大费用
        while(!q.empty())   q.pop();
        CL(vis, 0);
        CL(dis, -1);
        CL(pre, -1);
    
        q.push(S); dis[S] = 0;
        vis[S] = true; pre[S] = -1;
    
        int u, v, w, i;
        while(!q.empty()) {
            u = q.front(); q.pop();
            for(i = head[u]; i != -1; i = g[i].next) {
                v = g[i].to;
                w = g[i].cost;
                if(g[i].flow && dis[v] < dis[u] + w) {
                    dis[v] = dis[u] + w;
                    pre[v] = i;
                    if(!vis[v]) {
                        vis[v] = true; q.push(v);
                    }
                }
            }
            vis[u] = false;
        }
        return dis[T] != -1;
    }
    
    int get_flow() {    //增广路
        int tmp = T;
        int res = inf;
    
        while(pre[tmp] != -1) {
            res = min(res, g[pre[tmp]].flow);
            tmp = g[pre[tmp]].from;
        }
        tmp = T;
        while(pre[tmp] != -1) {
            g[pre[tmp]].flow -= res;
            g[pre[tmp]^1].flow += res;
            tmp = g[pre[tmp]].from;
        }
        return res;
    }
    
    bool solve() {
        int Cost = 0, Flow = 0;    //...
        while(spfa()) {
            Cost += dis[T];
            Flow += get_flow();
        }
        //printf("%d %d\n", Cost, Flow);
        //return Cost + n - Flow >= sumb;
    }

    例题:poj2516

    题解:http://www.cnblogs.com/vongang/archive/2012/04/14/2447566.html

     

  • 相关阅读:
    mysql重置id
    mysql数据类型
    手把手教你新建一个Vue项目
    用markdown开始优雅的写作
    源码阅读心得
    断点调试-程序员的必修课
    代码还是短点好!
    GoJS v1.8.27 去水印方法
    VS code不用集成终端如何修改并推送分支?
    LeetCode日拱一卒
  • 原文地址:https://www.cnblogs.com/vongang/p/2455468.html
Copyright © 2011-2022 走看看