洛谷 P5304 题解
type
status
date
slug
summary
tags
category
icon
password
题目大意:给定一张 n 个点 m 条边的有向图.
给定 k 个特殊点,求它们两两之间最短路的最小值.
20pts 做法:
枚举每个特殊点,跑一遍 dijkstra 更新答案
时间复杂度 O(kmlogm)
100pts 做法:
注意到我们并不关心具体是哪两个点使答案最优,因此可以建立超级源点 S 和超级汇点 T ,将 k 个特殊点分为两组,分别连向 S 和 T.
如何分组才能使所有路径都被统计过一遍?
Trick:
按照二进制位分别分组,对于每一位,将这一位为 0 的分为一组,这一位为 1 的分为一组.
时间复杂度 O(mlogmlogn)
证明:
假设答案为 u → v 的最短路,由于 u = v, 因此 u , v 二进制表示中至少有一位不同.
#include <algorithm> #include <cstring> #include <iostream> #include <queue> #include <vector> #define CLOSE ios::sync_with_stdio(0), cin.tie(nullptr), cout.tie(nullptr) using namespace std; using ll = long long; const int N = 1e5 + 5; int n, m, k; struct Edge { int v; ll w; }; vector<Edge> G[N]; void add(int u, int v, ll w) { G[u].push_back({v, w}); } int c[N], x, y; ll z; struct dijnode { int u; ll d; bool operator<(const dijnode x) const { return x.d < d; } }; ll dis[N]; int vis[N]; ll dijkstra(int s, int t) { memset(dis, 0x3f, sizeof dis); memset(vis, 0, sizeof vis); priority_queue<dijnode> Q; dis[s] = 0; Q.push({s, 0}); while (!Q.empty()) { auto [u, d] = Q.top(); Q.pop(); if (vis[u]) continue; vis[u] = 1; for (auto [v, w] : G[u]) { if (dis[v] > dis[u] + w) { dis[v] = dis[u] + w; Q.push({v, dis[v]}); } } } return dis[t]; } int main() { CLOSE; int t; cin >> t; while (t--) { cin >> n >> m >> k; for (int i = 0; i <= n + 1; i++) G[i].clear(); for (int i = 1; i <= m; i++) cin >> x >> y >> z, add(x, y, z); for (int i = 1; i <= k; i++) cin >> c[i]; ll ans = 1e16; for (int i = 0; (1 << i) <= n; i++) { for (int j = 1; j <= n + 2; j++) { while (!G[j].empty() && G[j].back().w == 0) G[j].pop_back(); } for (int j = 1; j <= k; j++) if (c[j] & (1 << i)) add(n + 2, c[j], 0); else add(c[j], n + 1, 0); ans = min(ans, dijkstra(n + 2, n + 1)); } for (int i = 0; (1 << i) <= n; i++) { for (int j = 1; j <= n + 2; j++) { while (!G[j].empty() && G[j].back().w == 0) G[j].pop_back(); } for (int j = 1; j <= k; j++) if (c[j] & (1 << i)) add(c[j], n + 2, 0); else add(n + 1, c[j], 0); ans = min(ans, dijkstra(n + 1, n + 2)); } cout << ans << '\n'; } return 0; }
C++
Loading...