Codeforces Round #668 (Div.2) D. Tree Tag(博弈)(dfs)

D. Tree Tag

time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
Alice and Bob are playing a fun game of tree tag.

The game is played on a tree of 𝑛n vertices numbered from 11 to 𝑛n. Recall that a tree on 𝑛n vertices is an undirected, connected graph with 𝑛−1n−1 edges.

Initially, Alice is located at vertex 𝑎a, and Bob at vertex 𝑏b. They take turns alternately, and Alice makes the first move. In a move, Alice can jump to a vertex with distance at most da from the current vertex. And in a move, Bob can jump to a vertex with distance at most 𝑑𝑏db from the current vertex. The distance between two vertices is defined as the number of edges on the unique simple path between them. In particular, either player is allowed to stay at the same vertex in a move. Note that when performing a move, a player only occupies the starting and ending vertices of their move, not the vertices between them.

If after at most 1010010100 moves, Alice and Bob occupy the same vertex, then Alice is declared the winner. Otherwise, Bob wins.

Determine the winner if both players play optimally.

Input
Each test contains multiple test cases. The first line contains the number of test cases 𝑡t (1≤𝑡≤1041≤t≤104). Description of the test cases follows.

The first line of each test case contains five integers 𝑛,𝑎,𝑏,𝑑𝑎,𝑑𝑏n,a,b,da,db (2≤𝑛≤1052≤n≤105, 1≤𝑎,𝑏≤𝑛1≤a,b≤n, 𝑎≠𝑏a≠b, 1≤𝑑𝑎,𝑑𝑏≤𝑛−11≤da,db≤n−1) — the number of vertices, Alice’s vertex, Bob’s vertex, Alice’s maximum jumping distance, and Bob’s maximum jumping distance, respectively.

The following 𝑛−1n−1 lines describe the edges of the tree. The 𝑖i-th of these lines contains two integers 𝑢u, 𝑣v (1≤𝑢,𝑣≤𝑛,𝑢≠𝑣1≤u,v≤n,u≠v), denoting an edge between vertices 𝑢u and 𝑣v. It is guaranteed that these edges form a tree structure.

It is guaranteed that the sum of 𝑛n across all test cases does not exceed 105105.

Output
For each test case, output a single line containing the winner of the game: “Alice” or “Bob”.

Example
inputCopy
4
4 3 2 1 2
1 2
1 3
1 4
6 6 1 2 5
1 2
6 5
2 3
3 4
4 5
9 3 9 2 5
1 2
1 6
1 9
1 3
9 5
7 9
4 8
4 3
11 8 11 3 3
1 2
11 9
4 9
6 5
2 10
3 2
5 9
8 3
7 4
7 10
outputCopy
Alice
Bob
Alice
Alice
Note
In the first test case, Alice can win by moving to vertex 11. Then wherever Bob moves next, Alice will be able to move to the same vertex on the next move.

In the second test case, Bob has the following strategy to win. Wherever Alice moves, Bob will always move to whichever of the two vertices 11 or 66 is farthest from Alice.
此题的大意:有一颗树,A和B开始时分别在树上a点和b点,一次a最多能走da步,一次b最多能走db步,A先出发,问A是否能够捉到B?(A与B都足够聪明)
思路:如果在开始时dis(a,b)<=da,那么可以判断A一步可以捉到B(即A所在位置与B重合)否则再判断如果树的直径D<=da2那么A一定可以捉到B,这个是因为如果条件成立,那么A首先要走到树中心点(即该点与其他点的距离<=D)那么无论B在哪里,A均可以一步到达;如果该条件不成立,我们再来判断一下B获胜的条件,可以看出,db如果大于2×da的话B所做的策略将是尽可能远离A,直到树的一个叶子,此时就应该等着A,若A进入B以da为半径的范围内,B可以一下跳出到至少2×da+1步(面向A),B,A之间的距离依然是大于da(即A一步到达不了)这时的我们就不用考虑该树是否够深的问题,因为在刚才的判断里D是<=da×2的,因而在这里D一定>da2所以是有足够的空间让B逃跑的,那否则A就一定能捉到B,因为A只需要将B逼到一片叶子上,然后跳到距离B半径为da的点上,若B选择逃跑,我们将db设为最大:2×da,这时的A无论B跳到哪里,都只需要一步就可以抓住B;

该题代码中dfs做了3件事:
1是运用一个len,它代表当前遍历到的最深的深度;
2是运用d求树的直径,主要是在遍历一个新的点时,此时的len还未更新,这时我们可以用dfs知道该点的最大深度,前面点最深的深度+该点最大深度,与直径取一个max放入直径中
3是用deep数组标记与a点的距离,深度每下降一次,deep+1;该方法是为了dfs求a,b两点间的距离

所有情况分析完毕,该题的思路与代码均有借鉴cf官方题解;
代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#define ll long long
using namespace std;
vector<int>G[100009];
int deep[100009],d;
int dfs(int a,int b){
    int len=0;
    for(int i:G[a]){
        if(i!=b){//下面写dfs(i,a),就是因为这里写了b不进该循环,当然你也可以建vis数组维护;
            deep[i] = deep[a] + 1;
            int sz = dfs(i,a) + 1;//遍历到的该点的深度
            d = max(d,sz+len);//维护d,上面分析有讲到
            len = max(len,sz);//维护len,若有更深深度,则变化
        }
    }
    return len;
}
void solve(){
    int _;
    scanf("%d",&_);
    while(_--){d=0;
        int a,b,da,db,n;
        scanf("%d%d%d%d%d",&n,&a,&b,&da,&db);
        for(int i=1;i<=n;++i){
            G[i].clear();
        }
        for(int i=1;i<n;++i){
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        deep[a] = 0;//初始化a的深度
        dfs(a,-1);
        if(deep[b]<=da)puts("Alice");
        else {
            if(d<=da*2)puts("Alice");
            else if(da*2<db)puts("Bob");
            else puts("Alice");
        }
    }
}
int main()
{
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值