P1135 奇怪的电梯 题解。
首先这种简单最短路的题,首先是建图然后再是最短路,我们伟大的费用流正好可以解决这一类的问题,这道题你只需要 分别向 连 的边然后跑最小费用最大流就可以轻松解决这个问题了。
但是这道题有一点不一样,直接跑可能流量大于 ,但是最短路是只能有一条的,可恶的最短路,可惜就算你路径有几条我伟大的费用流也能跑出正确最短路,怎么做呢?
我们只需要建一个新的汇点 然后 向 连 的边,而最短路只能有一条?根本不在乎,我们直接这样连边,流量就不超过 了,这样做就是对的,这世间,还有什么能够阻挡!!!!!还有什么能够阻挡我们的费用流算法!!!!!!!!!
时间复杂度 ,可能还有一点小常数不过没有人在乎,这就是网络流算法的魅力,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; }
cpp