原题链接:
https://acm.hznu.edu.cn/OJ/problem.php?id=2977https://acm.hznu.edu.cn/OJ/problem.php?id=2977
Description
俊俊终于打败了深渊法师, 来到了npy的面前。 npy说, 你要跟我玩个游戏, 只有你过关了, 我才会跟你走。他们决定玩宝可梦的游戏。在npy自制的简易宝可梦中,每只宝可梦都有且只有水, 火, 草中的一个属性(水 > 火 > 草 > 水, 其中>表示克制关系), 两只宝可梦对战时, 若存在属性克制, 则效果拔群。现在有n只宝可梦, npy决定, 不告诉俊俊每只宝可梦的具体属性, 只给出m条提示, 每条提示包括两只宝可梦的克制关系。最后俊俊和npy各从池子中抽出一只宝可梦进行对决, 若俊俊胜利了, 则可以带走npy。
聪明的俊俊知道他的胜算并不高, 但是他太想带走npy了。在他的苦苦哀求(死缠烂打)之下, npy被感动了, 决定给俊俊一个特殊技能:比赛开始前, 俊俊可以发动技能, 交换他们两个的宝可梦
Input
第一行两个整数n,m(2 <= n <= 100000, 1 <= m <= 100000), 表示一共有n只宝可梦和m个提示
接下来的m行, 每行给出两个整数x, y(1 <= x, y <= n)。表示宝可梦x克制y
最后一行给出两个整数a, b 分别表示俊俊的宝可梦和npy的宝可梦
数据保证读完所有的提示后, 任意两只宝可梦的克制关系都已知,且不存在克制关系冲突的情况
Output
如果俊俊的宝可梦克制npy的宝可梦, 他就会充满自信的喊一句“wait for me, my dear!”
如果俊俊的宝可梦被克制, 他就会发动技能大喊“change! change! change!”
如果两者的宝可梦属性相同,他就会对充满悬念的战局感到担忧, 说“can I win the game?”
请输出俊俊说的话
Sample
input Copy
3 2
1 2
2 3
3 1
output Copy
wait for me, my dear!
解题思路:较基础的种族并查集考察,相较于普通的并查集,这里我们要维护水 > 火 > 草 > 水这个克制关系,因此我们引入d[x]数组来表示该节点和根节点的距离;
我们不妨设根节点以及到根节点的距离%3==0的点为水,到根节点的距离%3==1的点为草(草克水),到根节点的距离%3==2的点为火(火克草)。
这样我们的克制关系可以整理为下图:
我们可以看出,互相克制的两个宝可梦在%3后的距离差为1,因此判断两个宝可梦a是否克制b的公式即 if(!(d[a]-d[b]-1)%3) 是否相同的公式为 if(!(d[a]-d[b])%3)
除此之外我们还要一个特殊情况:当输入的a和b不在集合中时,应该如何处理
ac代码:
#include <bits/stdc++.h>
using namespace std;
int p[100010],d[100010];
int find(int x)
{
if(p[x]!=x)
{
int t=find(p[x]);
d[x] +=d[p[x]];
p[x]=t;
}
return p[x];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,m;
cin >> n >> m;
for (int i=1;i<=n;i++) p[i]=i;
while (m--)
{
int x,y;
cin >> x >> y;
int px=find(x),py=find(y);
if(py!=px) {
p[px] = py;
d[px] = d[y] + 1 - d[x];
}
}
int a,b;
cin >> a >> b;
a1:
int px=find(a);
int py=find(b);
if(py==px)
{
if((d[a]-d[b]-1)%3==0) cout << "wait for me, my dear!";
else if((d[a]-d[b])%3==0) cout << "can I win the game?";
else cout << "change! change! change!";
}else if(px!=py)
{
p[px]=py;
d[px]=d[b]+1-d[a];
goto a1;
}
return 0;
}
写在最后:建议读者在了解并查集的基础上再来看这篇文章和写这道题,要不然可能会难以理解,本人表达能力欠佳,如有纰漏多多包涵,欢迎批评,感谢qwq