网络流-费用流zkw算法

基础费用流

进行SPFA每次对残余网络求最短路,记录前驱,然后跑这条增广路,更新答案,直到源点和汇点不连通位置

改良

我们可以类似dinic,在spfa求完每个点到源点的距离之后,再像dinic一样进行增广,这样就能多路增广,并且还可以加当前弧优化。

代码

#include <bits/stdc++.h>

using namespace std;

const int MAXN = 5e3 + 5;
const int INF = 0x3f3f3f3f;

int n, m;

struct Edge{
    int to, val, cost;
    Edge *next, *ops;
    Edge(int to, int val, int cost, Edge *next): to(to), val(val), cost(cost), next(next){}
};

Edge *head[MAXN];

void AddEdge(int u, int v, int w, int c) {
    head[u] = new Edge(v, w, c, head[u]);
    head[v] = new Edge(u, 0, -c, head[v]);
    head[u]->ops = head[v]; head[v]->ops = head[u];
}

namespace zkw{
    int s, t, ans, res;
    int dis[MAXN];
    bool vis[MAXN];
    //Edge *cur[MAXN];
    bool Spfa() {
        memset(vis, false, sizeof vis);
        memset(dis, 0x3f, sizeof dis);
        deque<int> q;
        q.push_back(s);
        vis[s] = true; dis[s] = 0;
        while (!q.empty()) {
            int u = q.front(); q.pop_front(); vis[u] = false;
            for (Edge *e = head[u]; e; e = e->next) {
                int v = e->to;
                if (e->val > 0 && dis[u] + e->cost < dis[v]) {
                    dis[v] = dis[u] + e->cost;
                    if (!vis[v]) {
                        vis[v] = true;
                        if (!q.empty() && dis[v] < dis[q.front()]) q.push_front(v);
                        else q.push_back(v);
                    }
                }
            }
        }
        return dis[t] < INF;
    }
    
    int Dfs(int u, int flow) {
        if (u == t) {
            vis[u] = true;
            res += flow;
            return flow;
        }
        int used = 0; vis[u] = true;
        for (Edge *e = head[u]; e; e = e->next) {
            int v = e->to;
            if ((!vis[v] || v == t) && e->val && dis[u] + e->cost == dis[v]) {
                int mi = Dfs(v, min(e->val, flow - used));
                if (mi) {
                    e->val -= mi;
                    e->ops->val += mi;
                    ans += e->cost * mi;
                    used += mi;
                }
                if (used == flow) break;
            }
        }
        return used;
    }
    
    void Work() {
        res = 0; ans = 0;
        while (Spfa()) {
            vis[t] = true;
            while (vis[t]) {
                memset(vis, false, sizeof vis);
                Dfs(s, INF);
            }
        }
    }
}

int main() {
    cin >> n >> m >> zkw :: s >> zkw :: t;
    for (int i = 1; i <= m; i++) {
        int u, v, w, c;
        cin >> u >> v >> w >> c;
        AddEdge(u, v, w, c);
    }
    zkw :: Work();
    cout << zkw :: res << ' ' << zkw :: ans << endl;
    return 0;
}

  

posted @ 2019-03-09 12:00  Noire02  阅读(266)  评论(0编辑  收藏  举报
Live2D