csp赛前刷题 搜索篇 Tales of seafaring
https://www.luogu.com.cn/problem/P3556
题意分析
注意题目中的 “(不一定是简单路径)”,也就是说可以在一条边重复走多次,也就是可以在两个点之间反复横跳
反复横跳意味着什么,如果从 ss (起点)走到 tt (终点)如果没有 dd 那么长,比 dd 要短,可以在最后两个点不断来回重复走,使路径 =d=d ,但是要注意一点,反复横跳每次都会把路径长度 +2+2。
所以 ss 走到 tt 的路径必须是和 dd 奇偶性相同,我们只需要求出 ss 到 tt 的奇数最短路径和偶数最短路径即可。
那么怎么找呢?我们又发现它的边权全都是1,所以我们用奇数最短路来更新偶数最短路,用偶数最短路来更新奇数最短路。另外,因为有很多询问的起点都是一样的,所以我们珂以离线来做。
然而还并没有结束。就像下面这组数据:
1 0 1
1 1 2
应该输出NIE,但我们会发现我们的程序输出的是TAK,为什么呢?因为我们对1号节点赋的初值为0,但我们在后面并没有更新它,所以我们应该记录一下我们队列里进了几个元素,倘若只进了一个元素,就说明这是一个孤立的点,那就是不存在了。
还要注意此题为无向图
🆗 上代码:
#include<algorithm> #include<iostream> #include<cstring> #include<queue> #include<cstdio> using namespace std; int n, m, x, y, z, k, s, t, tot, las; const int N = 1000100, inf = 999999999; int head[N], fa[N], dis1[N], dis2[N]; bool vis[N], ans[N]; struct bian { int to, nt; }e[N]; struct ask { int s, t, lu, id; friend bool operator <(const ask& a, const ask& b) { return a.s < b.s; } }Q[1000100]; void add(int f, int t) { e[++tot].to = t; e[tot].nt = head[f]; head[f] = tot; } int find(int x) { return x == fa[x] ? fa[x] : fa[x] = find(fa[x]); } void he(int x, int y) { fa[find(x)] = fa[find(y)]; } queue<int>q; void spfa(int s) { int x, in = 0; for (int i = 1; i <= n; ++i)dis1[i] = dis2[i] = inf; dis2[s] = 0; q.push(s); vis[s] = 1; while (!q.empty()) { x = q.front(); q.pop(); vis[x] = 0; in++; for (int i = head[x]; i; i = e[i].nt) { if (dis2[e[i].to] > dis1[x] + 1) { dis2[e[i].to] = dis1[x] + 1; if (!vis[e[i].to]) { q.push(e[i].to); vis[e[i].to] = 1; } } if (dis1[e[i].to] > dis2[x] + 1) { dis1[e[i].to] = dis2[x] + 1; if (!vis[e[i].to]) { q.push(e[i].to); vis[e[i].to] = 1; } } } } if (in == 1)dis1[s] = dis2[s] = inf; for (int i = las; Q[i].s == Q[las].s; ++i) { if (Q[i].lu & 1)ans[Q[i].id] = (dis1[Q[i].t] <= Q[i].lu); else ans[Q[i].id] = (dis2[Q[i].t] <= Q[i].lu); } } int main() { cin >> n >> m >> k; for (int i = 1; i <= n; ++i)fa[i] = i; for (int i = 1; i <= m; ++i) { cin>>x>>y; he(x, y); add(x, y); add(y, x); } for (int i = 1; i <= k; ++i) { cin>>Q[i].s>>Q[i].t>>Q[i].lu; Q[i].id = i; if (Q[i].s > Q[i].t)swap(Q[i].s, Q[i].t); } sort(Q + 1, Q + 1 + k); for (int i = 1; i <= k; ++i) { while (Q[i].s == Q[las].s)++i; las = i; spfa(Q[i].s); } for (int i = 1; i <= k; ++i) { if (ans[i])cout << "TAK" << endl; else cout<<"NIE"<<endl; } fclose(stdin); fclose(stdout); return 0; }