LOADING

加载过慢请开启缓存 浏览器默认开启

P1135 奇怪的电梯

2023/11/24 OI 题解

P1135 奇怪的电梯 题解。

首先这种简单最短路的题,首先是建图然后再是最短路,我们伟大的费用流正好可以解决这一类的问题,这道题你只需要 \(i\) 分别向 \(i \pm K_i\)\((1, 1)\) 的边然后跑最小费用最大流就可以轻松解决这个问题了。

但是这道题有一点不一样,直接跑可能流量大于 \(1\),但是最短路是只能有一条的,可恶的最短路,可惜就算你路径有几条我伟大的费用流也能跑出正确最短路,怎么做呢?

我们只需要建一个新的汇点 \(B'\) 然后 \(B\)\(B'\)\((1, 0)\) 的边,而最短路只能有一条?根本不在乎,我们直接这样连边,流量就不超过 \(1\) 了,这样做就是对的,这世间,还有什么能够阻挡!!!!!还有什么能够阻挡我们的费用流算法!!!!!!!!!

时间复杂度 \(O(n^3)\),可能还有一点小常数不过没有人在乎,这就是网络流算法的魅力,BFS 这种逆时代浪潮的做法迟早被淹没在费用流恐怖的实力之下!!!

大概就是上面这样。

#include <bit>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
using u32 = unsigned;
using p32 = pair<int, int>;
const int N = 205, M = 405, INF = 0x3f3f3f3f;
int n, s, t, tt, a[N], h[N], dis[N], pos[N], siz[35], cur[N], head[N],
    cnt = 1, beg, top, flow, cost;
bool vis[N];
struct edge {
    int to, nex, w, c;
} e[M << 1];
queue<int> Q;
vector<int> buc[35], tmp;
void add(int u, int v, int w, int c) { e[++cnt] = {v, head[u], w, c}, head[u] = cnt; }
void addflow(int u, int v, int w, int c) { add(u, v, w, c), add(v, u, 0, -c); }
void spfa() {
    memset(h, 0x3f, sizeof(h));
    h[s] = 0, vis[s] = true, Q.push(s);
    while (!Q.empty()) {
        int u = Q.front();
        vis[u] = false, Q.pop();
        for (int i = head[u]; i; i = e[i].nex) {
            int v = e[i].to, w = e[i].w, c = e[i].c;
            if (h[v] > h[u] + c && w) {
                h[v] = h[u] + c;
                if (!vis[v]) vis[v] = true, Q.push(v);
            }
        }
    }
}
// radix heap
void insert(int x) {
    int k = bit_width<u32>(dis[x] ^ dis[top]);
    ++siz[k], pos[x] = buc[k].size(), buc[k].push_back(x);
}
void update(int x, int y) {
    int k = bit_width<u32>(dis[x] ^ dis[top]);
    --siz[k], dis[x] = y, insert(x);
}
void removemin() {
    pos[top] = -1, --siz[0];
    if (siz[0]) {
        while (pos[top = buc[0][beg]] == -1) ++beg;
        return;
    }
    int cur = 0, las = top;
    for (int i = 30; i >= 1; i--)
        if (siz[i]) cur = i;
    siz[cur] = beg = top = 0, tmp = move(buc[cur]);
    for (int i = 0; i <= cur; i++) buc[i].clear();
    for (int i = 0; i < (int)tmp.size(); i++) {
        int k = bit_width<u32>(dis[tmp[i]] ^ dis[las]);
        if (k == cur && pos[tmp[i]] == i && dis[tmp[i]] < dis[top]) top = tmp[i];
    }
    for (int i = 0; i < (int)tmp.size(); i++) {
        int k = bit_width<u32>(dis[tmp[i]] ^ dis[las]);
        if (k == cur && pos[tmp[i]] == i) insert(tmp[i]);
    }
}
bool dijkstra() {
    memset(dis, 0x3f, sizeof(dis));
    dis[top = s] = beg = 0;
    for (int i = 0; i <= 30; i++) siz[i] = 0, buc[i].clear();
    for (int i = 1; i <= n + 1; i++) insert(i);
    for (int i = 1; i <= n + 1; i++, removemin()) {
        if (dis[top] == INF) break;
        for (int j = head[top]; j; j = e[j].nex) {
            int v = e[j].to, w = e[j].w, c = e[j].c;
            if (dis[v] > dis[top] + c + h[top] - h[v] && w)
                update(v, dis[top] + c + h[top] - h[v]);
        }
    }
    return dis[t] != INF;
}
int dfs(int u, int flow) {
    if (u == t) return flow;
    int used = 0;
    vis[u] = true;
    for (int &i = cur[u]; i; i = e[i].nex) {
        int v = e[i].to, w = e[i].w, c = e[i].c;
        if (!vis[v] && dis[v] == dis[u] + c + h[u] - h[v] && w) {
            int ret = dfs(v, min(flow - used, w));
            used += ret, e[i].w -= ret, e[i ^ 1].w += ret;
            if (used == flow) break;
        }
    }
    vis[u] = false;
    return used;
}
void dinic() {
    int ret;
    spfa();
    while (dijkstra()) {
        memcpy(cur, head, sizeof(cur));
        memset(vis, 0, sizeof(vis));
        while ((ret = dfs(s, INF))) flow += ret, cost += ret * (dis[t] + h[t]);
        for (int i = 1; i <= n + 1; i++) h[i] += dis[i];
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> s >> tt, t = n + 1;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        if (i - a[i] >= 1) addflow(i, i - a[i], 1, 1);
        if (i + a[i] <= n) addflow(i, i + a[i], 1, 1);
    }
    addflow(tt, t, 1, 0);
    dinic();
    if (flow == 1) cout << cost;
    else cout << "-1";
    return 0;
}