【题解】[COCI2020-2021#5] Magenta

solution:

图论 + 博弈论。

我们称操作前两个棋子间距离为偶数的一方为 猎人 ,不难发现 猎人 只会 win 或者 draw。这是因为终止状态中棋子的距离为 0 0 0 ,而 猎人 操作后一定是奇数,所以不可能走到对方的棋子上。当然要特判 猎人 一条边都走不到的情况。

考虑将图中所有的红色边都删除,形成若干连通块。将猎人连通块外的节点设为 1 1 1 。我们从猎人开始搜索,并记录下到达当前节点的最小步数。然后从猎物开始搜索,当且仅当当前步数小于所标记步数或当前点权值为 1 1 1 时这个点可以扩展,如果遍历到一个权值为 1 1 1 的出口并且这个点有后续连接的权值为 1 1 1 的点,则形成平局;否则无法逃脱。

一波剧烈恶心讨论。

  1. a a a 先手没有地方可走,输出 Marin ;
  2. b b b 没有合法出边,输出 Paula;
  3. L o s e Lose Lose 能走到权值为 1 1 1 的点,并且这个点有后续连接的权值为 1 1 1 的点(这类节点可以预处理),输出 Magenta ;
  4. 否则输出 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() { // freopen("data.in","r",stdin); 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; } // printf("%d %d\n",Win,Lose); 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__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530286.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(14)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示