费用流

边们增加了费用 求费用最少的最大流

在残余网络中,用spfa跑费用的最短路,然后沿着这条花费最少的增广路进行增广

(表示怀疑这样做的时间复杂度会比较高 因为他甚至都没有沿着分层图上最短路去增广...不过貌似没有别的办法...)

 看起来很容易出现负圈并且死循环的样子 负圈的问题感觉大佬解释得比较清楚:

 

 在费用最短路增广的过程中产生的剩余网络不可能存在负圈,原因是最短增广路增广能够保证每次迭代的结果是当前流下的费用

最小的解。因此如果存在负圈的话消去这个负圈就能达到一个更小的费用,这和前面那个性质矛盾。至于那个性质的证明是对流量

进行归纳来完成的。

 

大概就是不含初始负圈的话不会产生负圈吧...

(链接:http://bbs.csdn.net/topics/300017499?fps=1&locationNum=10) 

void addedge(int u, int v, int w, int cost){
    edge[tot] = Edge(u, v, w, 0, cost, head[u]);
    head[u] = tot++;
    edge[tot] = Edge(v, u, 0, 0, -cost, head[v]);
    head[v] = tot++;
}
bool spfa(int st, int ed){
    queue<int>Q;
    memset(pre, -1, sizeof pre);
    memset(inq, 0, sizeof inq);
    memset(d, inf, sizeof d);
    inq[st] = 1;
    d[st] = 0;
    Q.push(st);
    while(!Q.empty()){
        int u = Q.front();
        Q.pop();
        inq[u] = 0;
        for(int i = head[u]; ~i; i = edge[i].nxt){
            int v = edge[i].v, cost = edge[i].cost;
            if(d[v] > d[u]+cost && edge[i].w-edge[i].f){
                d[v] = d[u]+cost;
                pre[v] = i;
                if(!inq[v]){
                    inq[v] = 1;
                    Q.push(v);
                }
            }
        }
    }
    return pre[ed] != -1;
}
int MCMF(int st, int ed){
    int flow = 0;
    ans = 0;
    while(spfa(st, ed)){
        int MIN = inf;
        for(int i = pre[ed]; ~i; i = pre[edge[i^1].v]){
            if(MIN > edge[i].w-edge[i].f)
                MIN = edge[i].w-edge[i].f;
        }
        for(int i = pre[ed]; ~i; i = pre[edge[i^1].v]){
            edge[i].f += MIN;
            edge[i^1].f -= MIN;
        }
        ans += d[ed]*MIN;
        flow += MIN;
    }
    return flow;

 

转载于:https://www.cnblogs.com/DearDongchen/p/7624325.html

你可能感兴趣的:(费用流)