1 条题解
-
0
自动搬运
来自洛谷,原作者为

Z1qqurat
一条 2 米长的翻车鱼死在了我家后院搬运于
2025-08-24 22:36:36,当前版本为作者最后更新于2024-01-02 17:03:26,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
这里直接从链入手而没有讲 的那种暴力排除法是因为个人认为对正解启发性不大。首先容易排除 的情况因为如果有环的话那么 B 可以反复横跳以至于 A 永远猜不到。
然后发现有链的特殊性质,考虑图是一条 的链的情况。不难想到的是 $1\to 2 \to 3 \to \cdots \to n-1 \to n \to n \to n-1\to \cdots \to3\to2\to1$ 的构造,因为它总能将 B 逼到无路可走。但是这一定是最优的策略吗?是否能在更少的步数内使 B 无路可走呢?我们先试着证明这种构造是怎么把 B 逼到无路可走的。将链黑白染色,偶数点为黑,奇数点为白,并且设 表示 A 猜测的点形成的路径(由于要确定 B 的相对方向所以 A 一定是猜相邻的点,所以一定是一条路径), 表示 B 走的路径。发现本质就是通过同色异色点来抓住的,容易发现其实 根本不用猜,那么策略简化为了 $2 \to 3 \to \cdots \to n-2 \to n-1 \to n-1 \to n-2\to \cdots \to3\to2$。
接下来证明为什么这个策略是正确的。如果 B 一开始在一个偶数点,那么它就和前 轮()中 A 的位置颜色相同。假如 ,那么 。易得如果存在 ,那么一定存在时刻 使得 相遇了,那么 B 就被抓住了。所以如果 B 不想被抓,那么它就一定满足这 轮都有 ,而 奇偶性相同,故 ,而如果要这么一直保持下去,在前 轮中 B 一定会无路可走。而 为奇数点的情况是同理的,因为 会被连续问两次,所以在后 轮,A,B 会在同奇偶的点上,证明同上。
接下来考虑链上挂一个点的情况:

由于仍然满足染色奇偶性的情况,所以要么会在第一段()中排除要么在第二段,对答案没有任何影响。
如果链上挂两个点?

如果不去这两个点中任何一个,那么 B 可以在这两个点上反复横跳不被抓到(因为这条附加链拥有了两种颜色了),所以必须将其加入询问段,问两遍,仍然是有解的(也就是说如果有附加链 ,那么在询问段中把 改成问 )。
如果链上挂了三个点?

你会发现如果还往这个链上询问,那么要花去的额外步数已经足以让原先在主链一侧的 B 去到另一侧了,也就是说 A 无法确定 B 的方位,自然就无解了。当附加链长度 时都无解。
但是还会发现有类似这样的情况:有多条交在一起的长为 的附加链。

其实根据长为 的附加链不影响策略的结论,我们容易发现只需要任取其中一个深度为 的附加点去询问就可以了。实际上对做法影响不大。
然后具体实现就是将树的直径作为主链,对主链上点往外 dfs 判断即可。注意特判掉 的情况( 的时候是询问 )。代码实现不难。
#include <bits/stdc++.h> #define ALL(v) begin(v), end(v) #define All(v, l, r) &v[l], &v[(r) + 1] #define NOSOL return cout << "NO\n", 0 using i64 = int64_t; using std::cin; using std::cout; constexpr int N = 1005; int n, m, s, t, ex; std::array<std::vector<int>, N> G, ext; //extend points std::array<int, N> dis, fa; std::array<bool, N> vis; //on the diameter? std::vector<int> dia, path; //diameter auto dfs1(int u, int ff) -> void { fa[u] = ff; if (dis[u] > dis[t]) t = u; for (auto v : G[u]) if (v != ff) dis[v] = dis[u] + 1, dfs1(v, u); return ; } auto dfs2(int u, int ff) -> bool { fa[u] = ff; if (dis[u] >= 3) return 0; else if (dis[u] == 2) ex = u; for (auto v : G[u]) { if (v != ff && !vis[v]) { dis[v] = dis[u] + 1; if (!dfs2(v, u)) return 0; } } return 1; } auto main() -> int { std::ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); cin >> n >> m; for (auto i = 1, u = 0, v = 0; i <= m; ++i) cin >> u >> v, G[u].emplace_back(v), G[v].emplace_back(u); if (m != n - 1) NOSOL; if (n == 1) return cout << "YES\n1\n1\n", 0; if (n == 2) return cout << "YES\n2\n1 1\n", 0; dfs1(1, 0), s = t; dis[s] = 0, dfs1(s, 0); for (auto i = fa[t]; i && i != s; i = fa[i]) dia.emplace_back(i), vis[i] = 1; vis[s] = vis[t] = 1; for (auto x : dia) { for (auto y : G[x]) { if (vis[y]) continue; ex = 0, dis[y] = 1; if (!dfs2(y, x)) NOSOL; else if (ex) ext[x].emplace_back(y); } } for (auto x : dia) { path.emplace_back(x); for (auto y : ext[x]) path.emplace_back(y), path.emplace_back(x); } cout << "YES\n" << 2 * path.size() << "\n"; for (auto i : path) cout << i << ' '; reverse(ALL(path)); for (auto i : path) cout << i << ' '; return 0; }
- 1
信息
- ID
- 7294
- 时间
- 1000ms
- 内存
- 500MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者