P8173 Sol
这里直接从链入手而没有讲
然后发现有链的特殊性质,考虑图是一条
接下来证明为什么这个策略是正确的。如果 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;
}