// https://atcoder.jp/contests/abc067/tasks/arc078_b
// <博弈 + dfs>
// 关键点: 双方的最优策略一定是首先沿着两人间的最短路径进行染色,
// 当最短路径上的节点都被染色后, 两人就不存在冲突(争夺节点染色)了,
// 此后仅能在各自的区域内将未染色的分支节点染色,
// 按照上述策略找到最短路径上的分界点(染色情况), 统计双方总染色数进行比较即可
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
using LL = long long;
const int N = 1e5 + 10, INF = 0x3f3f3f3f;
vector<int> g[N];
int n;
int c[N]; // 染色: 1 black, 2 white
// 第一次遍历, 得到1~n的最短路径长度len, 计算分界点位置(len-1)/2
// 递归返回时, 对最短路径上的节点按策略进行染色
int dfs1(int u, int pa, int d)
{
if (u == n) // 找到节点n
{
c[u] = 2;
return (d-1) / 2; // 除n外, 最短路径上染成白色的节点数
}
for (auto &v: g[u])
{
if (v == pa) continue;
int t = dfs1(v, u, d+1);
if (t != INF)
{
// 当子结点返回值为正数(非INF), 则染成白色
// 若<=0, 则染成黑色
if (t > 0) c[u] = 2;
else c[u] = 1;
return t - 1; // 序号-1, 使得从白色过渡为黑色
}
}
return INF; // 不在最短路径上的节点返回INF
}
// 第二次遍历, 对余下的节点进行染色, 统计白色个数
void dfs2(int u, int pa, int &cnt)
{
cnt ++;
for (auto &v: g[u])
{
if (v == pa || c[v] == 2) continue;
dfs2(v, u, cnt);
}
}
void solv()
{
cin >> n;
int a, b;
for (int i = 1; i < n; i ++)
{
cin >> a >> b;
g[a].push_back(b);
g[b].push_back(a);
}
dfs1(1, 0, 0);
int cnt = 0;
dfs2(1, 0, cnt);
if (cnt > n/2) cout << "Fennec" << endl;
else cout << "Snuke" << endl;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T = 1;
// cin >> T;
while (T --)
{
solv();
}
return 0;
}
abc067d <博弈 + dfs>
发布时间 2023-07-10 11:01:00作者: O2iginal