题目链接
翻译
给你一棵树,一个人((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 imes dage diameter(T)), 其中 (diameter(T)) 表示树的直径。这种情况下, 只要 (Alice) 走到树的直径的中点上,那么下一次轮到 (Alice) 走的时候,她就可以走到树上的任意一个位置了,(Bob)也就无处藏身了,因此 (Alice) 赢。
- (db > 2 imes 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 imes da+1), 而 (db> 2 imes da),
所以 (Bob) 是肯定能一次移动到这么一个点 (v) 的。那么 (Bob) 也就每次都能在被抓的边缘疯狂试探了:), 因此 (Bob) 赢。这里保证存在这么一个点 (v) 的前提条件就是我们已经排除了第二种情况,不会出现所有的点 (Alice) 都能在一步之内走到。 - (db le 2 imes da), 这种情况,我们可以把 (Alice) 所在的点 (a) 看做是树的根节点,(b) 是在 (a) 的某个子树中的 (距离根节点 (v) 的距离大于 (da) ,而且会发现,因为 (db le 2 imes da), 所以 (a) 永远无法跳出它所在的子树到达另外一棵子树中去 (跳过去了也只会被抓到)。
所以,我们只要每次让 (Alice) 往 (b) 所在的子树下走一个节点 (这个时候 (d(a,b)) 最坏也只是变成 (2 imes da), 那么 (b) 依靠最大为 (2 imes da) 的 (db) 还是跳不出对应的子树),然后一步一步逼近 (b) 就可以了,所以这种情况仍然是 (Alice) 赢。
求出 (a) 到 (b) 的距离和 (da) 判断一下,然后求出树的直径, 和 (2 imes da) 比较一下, 最后用 (2 imes 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;
}