[机房测试]普通快乐
给定一个 \(n\) 个点 \(m\) 条边的无向图和 \(k\) 个关键点,求关键点间两两距离的最小值。
正解:
点两两距离最小值的套路是新建一个源点 \(S\) 和一个汇点 \(T\),都向关键点连边权为0的边,此时 \(S\) 到 \(T\) 的最短路就是答案?注意到我们从 \(S\) 走到一个点会直接走到 \(T\),最短路是0.所以我们考虑二进制分组,枚举位数 \(i\), 第 \(i\) 位为 1 的连向 \(S\),否则连向 \(T\),这样求出的就是两个集合之间的最短距离。显然每对点都会被枚举到。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <ctime>
using namespace std;
const int N = 200005;
int fr[N << 1], t[N << 1], w[N << 1];
struct edge {
int head, to, nxt, val;
} ed[N << 2];
int en = 0, dis[N], n, m, k, ans = 0x3f3f3f3f;
int b[N], top = 0, mp[N];
int vis[N];
bool c[N];
struct node {
int x, d;
inline node(int X, int D) : x(X), d(D) { }
inline bool operator > (const node &b) const { return d > b.d; }
inline bool operator < (const node &b) const { return d < b.d; }
};
priority_queue<node, vector<node>, greater<node> > q;
inline int min_(int a, int b) {
return a < b ? a : b;
}
inline int read() {
register int s = 0; register char ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) s = (s << 1) + (s << 3) + (ch & 15), ch = getchar();
return s;
}
inline void addedge(int from, int to, int val) {
ed[++en].to = to; ed[en].val = val; ed[en].nxt = ed[from].head; ed[from].head = en;
}
inline void dijkstra(int s) {
for (int i = 0; i <= en || i <= n + 2; ++i) ed[i].head = ed[i].to = ed[i].nxt = ed[i].val = 0;
en = 0;
for (int i = 1; i <= m; ++i) {
addedge(fr[i], t[i], w[i]); addedge(t[i], fr[i], w[i]);
}
int S = n + 1, T = n + 2;
for (int i = 1; i <= k; ++i) {
if ((i >> s) & 1) addedge(S, b[i], 0);
else addedge(b[i], T, 0);
}
for (int i = 1; i <= n + 2; ++i) dis[i] = 0x3f3f3f3f, vis[i] = 0;
dis[S] = 0; q.push(node(S, 0));
while (!q.empty()) {
int x = q.top().x; q.pop();
if (vis[x] == 1) continue; vis[x] = 1;
for (int i = ed[x].head; i; i = ed[i].nxt) {
int v = ed[i].to;
if (dis[v] > dis[x] + ed[i].val) {
q.push(node(v, dis[v] = dis[x] + ed[i].val));
}
}
} if (dis[T]) ans = min_(ans, dis[T]);
}
int main() {
// freopen("path.in", "r", stdin); freopen("path.out", "w", stdout);
n = read(); m = read(); k = read();
for (int i = 1; i <= m; ++i) {
fr[i] = read(); t[i] = read(); w[i] = read();
} for (int i = 1; i <= k; ++i) {
c[b[i] = read()] = 1; mp[b[i]] = i;
}
for (int i = 0; (1 << i) <= k; ++i) dijkstra(i);
printf("%d", ans); return 0;
}

浙公网安备 33010602011771号