最小费用最大流

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

定义:图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

 

 

posted @ 2012-04-18 16:07  AC_Von  阅读(321)  评论(0编辑  收藏  举报