1 条题解

  • 0
    @ 2025-8-24 22:36:36

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Z1qqurat
    一条 2 米长的翻车鱼死在了我家后院

    搬运于2025-08-24 22:36:36,当前版本为作者最后更新于2024-01-02 17:03:26,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    这里直接从链入手而没有讲 n20n\le 20 的那种暴力排除法是因为个人认为对正解启发性不大。首先容易排除 mnm\ge n 的情况因为如果有环的话那么 B 可以反复横跳以至于 A 永远猜不到。

    然后发现有链的特殊性质,考虑图是一条 1n1\to n 的链的情况。不难想到的是 $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 逼到无路可走的。将链黑白染色,偶数点为黑,奇数点为白,并且设 a1pa_{1\sim p} 表示 A 猜测的点形成的路径(由于要确定 B 的相对方向所以 A 一定是猜相邻的点,所以一定是一条路径),b1qb_{1\sim q} 表示 B 走的路径。发现本质就是通过同色异色点来抓住的,容易发现其实 1,n1,n 根本不用猜,那么策略简化为了 $2 \to 3 \to \cdots \to n-2 \to n-1 \to n-1 \to n-2\to \cdots \to3\to2$。

    接下来证明为什么这个策略是正确的。如果 B 一开始在一个偶数点,那么它就和前 n2n-2 轮(23n2n12 \to 3 \to \cdots \to n-2 \to n-1)中 A 的位置颜色相同。假如 b12b_1\ne2,那么 b1>a1b_1>a_1。易得如果存在 i<j,bi>ai,bj<aji<j,b_i>a_i,b_j<a_j,那么一定存在时刻 k(i,j)k\in (i,j) 使得 a,ba,b 相遇了,那么 B 就被抓住了。所以如果 B 不想被抓,那么它就一定满足这 n2n-2 轮都有 bi>aib_i>a_i,而 bi,aib_i,a_i 奇偶性相同,故 biai+2b_i\ge a_i+2,而如果要这么一直保持下去,在前 n2n-2 轮中 B 一定会无路可走。而 b1b_1 为奇数点的情况是同理的,因为 n1n-1 会被连续问两次,所以在后 n2n-2 轮,A,B 会在同奇偶的点上,证明同上。

    接下来考虑链上挂一个点的情况:

    p1

    由于仍然满足染色奇偶性的情况,所以要么会在第一段(23n2n12 \to 3 \to \cdots \to n-2 \to n-1)中排除要么在第二段,对答案没有任何影响。

    如果链上挂两个点?

    p1

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

    如果链上挂了三个点?

    p3

    你会发现如果还往这个链上询问,那么要花去的额外步数已经足以让原先在主链一侧的 B 去到另一侧了,也就是说 A 无法确定 B 的方位,自然就无解了。当附加链长度 3\ge 3 时都无解。

    但是还会发现有类似这样的情况:有多条交在一起的长为 22 的附加链。

    p4

    其实根据长为 11 的附加链不影响策略的结论,我们容易发现只需要任取其中一个深度为 22 的附加点去询问就可以了。实际上对做法影响不大。

    然后具体实现就是将树的直径作为主链,对主链上点往外 dfs 判断即可。注意特判掉 mn,n=1,n=2m\ge n,n=1,n=2 的情况(n=2n=2 的时候是询问 111 \to 1)。代码实现不难。

    #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
    上传者