solution:
图论 + 博弈论。
我们称操作前两个棋子间距离为偶数的一方为 猎人 ,不难发现 猎人 只会 win 或者 draw。这是因为终止状态中棋子的距离为
0
0
0 ,而 猎人 操作后一定是奇数,所以不可能走到对方的棋子上。当然要特判 猎人 一条边都走不到的情况。
考虑将图中所有的红色边都删除,形成若干连通块。将猎人连通块外的节点设为
1
1
1 。我们从猎人开始搜索,并记录下到达当前节点的最小步数。然后从猎物开始搜索,当且仅当当前步数小于所标记步数或当前点权值为
1
1
1 时这个点可以扩展,如果遍历到一个权值为
1
1
1 的出口并且这个点有后续连接的权值为
1
1
1 的点,则形成平局;否则无法逃脱。
一波剧烈恶心讨论。
- 若
a
a
a 先手没有地方可走,输出 Marin ;
- 若
b
b
b 没有合法出边,输出 Paula;
- 若
L
o
s
e
Lose
Lose 能走到权值为
1
1
1 的点,并且这个点有后续连接的权值为
1
1
1 的点(这类节点可以预处理),输出 Magenta ;
- 否则输出 Win==a?Marin:Paula。
很考验耐性。。
时间复杂度
O
(
n
)
O(n)
O(n) 。
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
#define PII pair<int,int>
using namespace std;
const int mx = 1e5 + 5;
int n, a, b, Win, Lose, vis[mx], vis2[mx], fa[mx], dis[mx], l, cnt, cnt2, res;
char op[10];
vector<PII> g[mx];
void dfs(int u, int f) {
fa[u] = f;
for (auto v : g[u]) {
if (v.first == f)
continue;
dfs(v.first, u);
}
}
void dfs2(int u, int fa, int step) {
dis[u] = step, cnt++;
vis[u] = 1;
for (auto v : g[u]) {
if (v.first == fa || v.second == Win)
continue;
dfs2(v.first, u, step + 1);
}
}
void dfs3(int u, int fa, int step) {
if (vis2[u]) {
printf("Magenta");
exit(0);
}
for (auto v : g[u]) {
if (v.first == fa || v.second == Lose)
continue;
if (step + 1 - (Lose == a) < dis[v.first]) {
dfs3(v.first, u, step + 1);
}
}
}
void dfs4(int u, int fa) {
cnt++;
for (auto v : g[u]) {
if (v.first == fa || v.first == b || v.second == a)
continue;
dfs4(v.first, u);
}
}
void dfs5(int u, int fa) {
cnt2++;
for (auto v : g[u]) {
if (v.first == fa || v.second == b)
continue;
dfs5(v.first, u);
}
}
signed main() {
scanf("%d%d%d", &n, &a, &b);
for (int i = 1; i < n; i++) {
int u, v, w;
scanf("%d%d%s", &u, &v, op);
if (op[0] == 'c')
w = a;
else if (op[0] == 'p')
w = b;
else
w = 0;
g[u].push_back(make_pair(v, w));
g[v].push_back(make_pair(u, w));
}
dfs(1, 0);
for (int i = a; i; i = fa[i]) {
vis[i] = 1;
dis[fa[i]] = dis[i] + 1;
}
if (vis[b]) {
l = dis[b];
} else {
for (int i = b; i; i = fa[i]) {
if (vis[fa[i]]) {
l = dis[fa[i]] + dis[i] + 1;
break;
}
dis[fa[i]] = dis[i] + 1;
}
}
Win = (l & 1) ? b : a, Lose = (l & 1) ? a : b;
for (int i = 1; i <= n; i++)
dis[i] = INF, vis[i] = 0;
dfs4(a, 0);
if (cnt == 1) {
printf("Marin");
return 0;
}
dfs5(b, 0);
if (cnt2 == 1) {
printf("Paula");
return 0;
}
dfs2(Win, 0, 0);
for (int i = 1; i <= n; i++) {
if (vis[i])
continue;
for (auto u : g[i]) {
if (!vis[u.first] && u.second != Lose) {
vis2[i] = 1;
break;
}
}
}
dfs3(Lose, 0, 0);
printf("%s", (Win == a) ? "Paula" : "Marin");
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」