题目链接
翻译
给你一棵树,一个人(\(Alice\))在 \(a\) 处,一个人(\(Bob\))在 \(b\) 处,其中 \(a\) 每次可以移动到距离(经过的边的个数)为 \(da\) 以内的任意一个点上,\(b\) 每次可以移动到距离为 \(db\) 以内的任意一个点上。
在 \(a\) 上的人 \(Alice\) 先移动,问 \(A\) 能否在有限次的移动过后和 \(Bob\) 在同一个节点上,如果能够做到, 那么 \(A\) 赢,否则 \(B\) 赢。\(A\) 和 \(B\) 都会采取有利于自己的最佳策略。
问你最后谁会赢。
题解
我们分成 \(4\) 类情况讨论:
- \(dis(a,b)\le da\), 那么显然 \(Alice\) 只需走一次,就能直接抓到 \(Bob\), 因此 \(Alice\) 赢。
- \(2\times da\ge diameter(T)\), 其中 \(diameter(T)\) 表示树的直径。这种情况下, 只要 \(Alice\) 走到树的直径的中点上,那么下一次轮到 \(Alice\) 走的时候,她就可以走到树上的任意一个位置了,\(Bob\)也就无处藏身了,因此 \(Alice\) 赢。
- \(db > 2\times da\), 因为已经排除了第一种情况,所以我们可以保证 \(Bob\) 能至少移动那么一次。我们可以采取这样的策略: 在 \(Alice\) 没有到达 \(Bob\) 的 \(da\) 范围以内,都按兵不动。一旦到了这个范围内,那么
\(Bob\) 和 \(Alice\) 的距离 \(d(a,b)\le da\),那么我们马上让 \(Bob\) 走到一个和 \(Alice\) 距离为 \(da+1\) 的点 \(v\) 处, 因为 \(d(b,a)\le da\), 那么 \(d(b,a)+d(a,v)\le da + da +1\), 即 \(d(b,v)\le 2\times da+1\), 而 \(db> 2\times da\),
所以 \(Bob\) 是肯定能一次移动到这么一个点 \(v\) 的。那么 \(Bob\) 也就每次都能在被抓的边缘疯狂试探了:), 因此 \(Bob\) 赢。这里保证存在这么一个点 \(v\) 的前提条件就是我们已经排除了第二种情况,不会出现所有的点 \(Alice\) 都能在一步之内走到。 - \(db \le 2\times da\), 这种情况,我们可以把 \(Alice\) 所在的点 \(a\) 看做是树的根节点,\(b\) 是在 \(a\) 的某个子树中的 (距离根节点 \(v\) 的距离大于 \(da\) ,而且会发现,因为 \(db \le 2\times da\), 所以 \(a\) 永远无法跳出它所在的子树到达另外一棵子树中去 (跳过去了也只会被抓到)。
所以,我们只要每次让 \(Alice\) 往 \(b\) 所在的子树下走一个节点 (这个时候 \(d(a,b)\) 最坏也只是变成 \(2\times da\), 那么 \(b\) 依靠最大为 \(2\times da\) 的 \(db\) 还是跳不出对应的子树),然后一步一步逼近 \(b\) 就可以了,所以这种情况仍然是 \(Alice\) 赢。
求出 \(a\) 到 \(b\) 的距离和 \(da\) 判断一下,然后求出树的直径, 和 \(2\times da\) 比较一下, 最后用 \(2 \times da\) 再和 \(db\) 比较一下就可以了。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5;
int n,a,b,da,db,d1,d2,nextX;
vector<int> g[N + 10];
void dfs1(int x,int fa,int mydis){
if (x == b){
d1 = mydis;
return;
}
int len = g[x].size();
for (int i = 0;i < len; i++){
int y = g[x][i];
if (y == fa){
continue;
}
dfs1(y,x,mydis + 1);
}
}
void dfs2(int x,int fa,int mydis){
if (mydis > d2){
nextX = x;
d2 = mydis;
}
int len = g[x].size();
for (int i = 0;i < len; i++){
int y = g[x][i];
if (y == fa){
continue;
}
dfs2(y,x,mydis+1);
}
}
int main(){
#ifdef LOCAL_DEFINE
freopen("E://9.AlgorithmCompetition//Visitor.txt","r",stdin);
#endif
ios::sync_with_stdio(0),cin.tie(0);
int T;
cin >> T;
while (T--){
for (int i = 1;i <= n; i++){
g[i].clear();
}
cin >> n >> a >> b >> da >> db;
for (int i = 1;i < n; i++){
int x, y;
cin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
dfs1(a, -1, 0);
if (da >= d1){
cout << "Alice" << endl;
continue;
}
d2 = 0;nextX = 1;
dfs2(a,-1,0);
d2 = 0;
dfs2(nextX,-1,0);
if (2*da >= d2){
cout << "Alice" << endl;
continue;
}
if (db > da*2){
cout << "Bob" << endl;
}else{
cout << "Alice" << endl;
}
}
return 0;
}