1. 程式人生 > 其它 >題解 BZOJ#4669. 搶奪

題解 BZOJ#4669. 搶奪

link

為什麼別人一眼二分答案然後就莽過去了,我想半天不知道咋二分。後來發現壓根不需要二分。

可以發現的性質是,我們一定優先走最短路,但是容量有限,一些較長路能夠分流。但是不管怎樣,我們一定走的是最短的若干條路徑。

首先建出費用流的圖,對於一條長為 \(d\) 的最短路以及流量 \(f\),答案為 \(d+(k-f-1)/f+1\)

而每新加入一條較劣的長為 \(d'\) 最短路,前 \(d\) 時間所有路徑分流,後 \(d'-d\) 的時間會讓之前的最短路儘量多通過人數。

不斷增廣然後取最優答案即可。

#include <bits/stdc++.h>

using i64 = long long;

const i64 Inf = 0x3f3f3f3f3f3f3f3f;

struct Graph {
    std::vector<int> head;
    struct Edge { int nxt, to; i64 flow, cost; };
    std::vector<Edge> e;
    Graph(int n) : head(n + 1, -1) {}
    void add(int u, int v, i64 f, i64 c) {
        e.emplace_back(Edge{head[u], v, f, c});
        head[u] = e.size() - 1;
    }
    void add_flow(int u, int v, i64 f, i64 c) {
        add(u, v, f, c);
        add(v, u, 0, -c);
    }
};

struct Dinic {
    Graph &G;
    std::vector<i64> dis;
    std::vector<int> cur, inq, vis;
    Dinic(int n, Graph &G)
        : G(G), dis(n + 1), cur(n + 1), inq(n + 1), vis(n + 1) {}
    i64 spfa(int S, int T) {
        std::fill(dis.begin(), dis.end(), Inf);
        std::queue<int> q;
        q.push(S);
        inq[S] = true;
        dis[S] = 0;
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            inq[u] = false;
            for (int i = G.head[u]; ~i; i = G.e[i].nxt) {
                int v = G.e[i].to;
                if (G.e[i].flow > 0 && dis[v] > dis[u] + G.e[i].cost) {
                    dis[v] = dis[u] + G.e[i].cost;
                    if (!inq[v]) {
                        q.push(v);
                        inq[v] = true;
                    }
                }
            }
        }
        return dis[T];
    }
    i64 dfs(int u, i64 lim, int T) {
        if (!lim || u == T)
            return lim;
        i64 rest = lim;
        vis[u] = true;
        for (int &i = cur[u]; ~i; i = G.e[i].nxt) {
            int v = G.e[i].to;
            if (G.e[i].flow > 0 && dis[v] == dis[u] + G.e[i].cost && !vis[v]) {
                i64 rlow = dfs(v, std::min(rest, (i64) G.e[i].flow), T);
                if (!rlow) dis[v] = Inf;
                G.e[i].flow -= rlow;
                G.e[i ^ 1].flow += rlow;
                rest -= rlow;
                if (!rest) break;
            }
        }
        vis[u] = false;
        return lim - rest;
    }
    i64 solve(int S, int T, i64 k) {
        i64 lastd = 0;
        i64 ans = Inf;
        i64 sumf = 0;
        while (k > 0) {
            i64 maxd = spfa(S, T);
            if (maxd == Inf)
                break;
            i64 flow = 0;
            i64 rlow;
            std::copy(G.head.begin(), G.head.end(), cur.begin());
            while (rlow = dfs(S, Inf, T), rlow > 0)
                flow += rlow;
            // std::cerr << maxd << ' ' << flow << '\n';
            k -= flow + (maxd - lastd) * sumf;
            sumf += flow;
            ans = std::min(ans, maxd + (k - 1) / sumf + 1);
            lastd = maxd;
        }
        return ans;
    }
};

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, m, k;
    while (std::cin >> n >> m >> k) {
        Graph G(n);
        for (int i = 0; i < m; ++i) {
            int u, v, w;
            std::cin >> u >> v >> w;
            ++u;
            ++v;
            G.add_flow(u, v, w, 1);
        }
        if (k == 0) {
            std::cout << 0 << '\n';
            continue;
        }
        i64 ans = Dinic(n, G).solve(1, n, k);
        if (ans == Inf)
            std::cout << "No solution" << '\n';
        else 
            std::cout << ans << '\n';
    }

    return 0;
}