【2020牛客多校九:树的BFS】K :The Flee Plan of Groundhog

【传送门】K :The Flee Plan of Groundhog

【难度】

4 / 10 4/10 4/10
认真想想也不会很难

【题意】

给定一棵树, n n n 个节点 , n − 1 n-1 n1 条边
每条边权 为 1
小G一开始在 一 号节点。
小O一开始在 n n n 号节点。
给定时间 t t t 秒。

(1)
一开始,小G向小O移动 t t t,速度1/s,小O 则不动。
(2)
t t t 秒后,小O 去追小G,小O的速度为2/s。
当然,此时小G会逃跑。
小G速度仍为1/s,但小G每回合可以移动或者不移动
但是小O每回合必须移动
(3)
每回合,先小G移动(或原地不动),再小O移动

求:小G在逃跑最优策略下,小O最少可以抓住小G的时间。

【数据范围】

1 ≤ n ≤ 1 0 5 1\le n\le10^5 1n105
1 ≤ t ≤ n − 1 1\le t\le n-1 1tn1
1 ≤ x , y ≤ n 1\le x,y\le n 1x,yn

【输入样例】

n    t n\quad \ \ t n  t
x 1 y 1 x_1\quad y_1 x1y1
      ⋮ \ \ \ \ \ \vdots      
x n − 1 y n − 1 x_{n-1}\quad y_{n-1} xn1yn1

7 2
1 2
2 5
5 7
5 6
3 6
3 4

【输出样例】

1

【解释】

【2020牛客多校九:树的BFS】K :The Flee Plan of Groundhog_第1张图片

【思路】

首先,易得:

(0)考虑 t t t 秒后,G在哪里

通过一次bfs,即可知道节点1 与节点n 之间的最短距离。
bfs时,记录每个节点的前驱结点即可知道 t t t 秒后G的所处位置。

(1)考虑G的基本的逃跑最优策略

若G逃跑,一定是向根节点或者叶子节点(后面称为角落)跑是最优的。
最优不可能来回跑。
最优不可能还没跑到角落就等待。
若已经被抓到了(当前秒时两个人都在同一个节点),则无法再逃跑。

(2)考虑G的逃跑方向

【2020牛客多校九:树的BFS】K :The Flee Plan of Groundhog_第2张图片

t t t 秒后G的位置如图所示,他应该哪个方向逃跑?

若小O处在 O 2 O2 O2 位置,可以看出G应该往 α \alpha α方向逃跑
若小O处在 O 1 O1 O1 位置,可以看出G应该往 β \beta β方向逃跑
γ \gamma γ方向总是最劣的。

这样,可能因为小O的位置不同,答案就截然不同,那么我们考虑:

d i s 2 [ i ] dis2[i] dis2[i]表示小G到节点 i i i 的最短时间
d i s 3 [ i ] dis3[i] dis3[i]表示小O到节点 i i i 的最短时间

如果某个节点存在 G到达时O还没到达或者正好抓住他
则答案为:
a n s = max ⁡ i {   d i s 3 [ i ] , 其 中 d i s 2 [ i ] ≤ d i s 3 [ i ]   } ans=\underset{i}{\max}\{\ dis3[i],其中dis2[i]\le dis3[i]\ \} ans=imax{ dis3[i],dis2[i]dis3[i] }

【注意】

========================================

这里取的是 d i s 3 [ i ] dis3[i] dis3[i] 而不是 d i s 2 [ i ] dis2[i] dis2[i] (之前打错了!)
因为如果 d i s 3 [ i ] dis3[i] dis3[i] 大的话,表示跑到这个节点,小G就原地等待小O追上他了。
而取最大值是因为小G逃跑策略永远是最优的,所以取大值。

========================================
很可惜,这样是不大正确的,因为小O每秒可以跑两个单位。

【2020牛客多校九:树的BFS】K :The Flee Plan of Groundhog_第3张图片
看图,可知对于节点1和2都成立,但是小G在节点2已经被抓到了,
他无法跑到节点1。

那么我们只要修改式子一下即可

a n s = max ⁡ i {   d i s 3 [ i ] , 其 中 d i s 2 [ i ] ≤ d i s 3 [ i ]   , 并 且 d i s 2 [ f a [ i ] ] < d i s 3 [ f a [ i ] ] } 其 中 f a [ i ] 表 示 i 的 前 驱 结 点 ans=\underset{i}{\max}\{\ dis3[i],其中dis2[i]\le dis3[i]\ ,并且 dis2[fa[i]] < dis3[fa[i]]\}\\ 其中fa[i]表示i的前驱结点 ans=imax{ dis3[i],dis2[i]dis3[i] ,dis2[fa[i]]<dis3[fa[i]]}fa[i]i

表示结点 i 正好O抓到了G,并且之前O还没抓到G。

【AC核心代码】

时间复杂度 O ( N ) O(N) O(N)

/*
 _            __   __          _          _
| |           \ \ / /         | |        (_)
| |__  _   _   \ V /__ _ _ __ | |     ___ _
| '_ \| | | |   \ // _` | '_ \| |    / _ \ |
| |_) | |_| |   | | (_| | | | | |___|  __/ |
|_.__/ \__, |   \_/\__,_|_| |_\_____/\___|_|
        __/ |
       |___/
*/
const int MAX = 1e5+50;

vector<int>G[MAX];
int dis[MAX];
int fa[MAX];
int n,t;

void bfs(){				/// 第一个bfs 计算t 时刻 G的位置等
    queue<int>Q;
    Q.push(1);
    dis[1] = 1;
    while(!Q.empty()){
        int x = Q.front();Q.pop();
        for(auto it : G[x]){
            if(!dis[it]){
                fa[it] = x;
                dis[it] = dis[x] + 1;
                Q.push(it);
            }
        }
    }
}
int dis2[MAX];
int dis3[MAX];
int yuan = 0;
void bfs2(int now){				///第二个bfs,计算dis2
    queue<int>Q;
    Q.push(now);
    dis2[now]=1;
    while(!Q.empty()){
        int x = Q.front();Q.pop();
        for(auto it : G[x]){
            if(!dis2[it]){
                dis2[it] = dis2[x] + 1;
                Q.push(it);
            }
        }
    }
}
int ans;
int fa2[MAX];
void bfs3(int now){    				///第三个bfs,计算dis3
    queue<int>Q;
    Q.push(now);
    dis3[now]=1;
    while(!Q.empty()){
        int x = Q.front();Q.pop();
        for(auto it : G[x]){
            if(!dis3[it]){
                fa2[it] = x;
                dis3[it] = dis3[x] + 1;
                Q.push(it);
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&t);
    for(int i=1;i<n;++i){
        int ta,tb;
        scanf("%d%d",&ta,&tb);
        G[ta].push_back(tb);
        G[tb].push_back(ta);
        fa[i] = i;
    }
    bfs();
    int ci = dis[n] - t - 1;
    int now = n;
    for(int i=0;i<ci;++i){
        now = fa[now];
    }
    bfs2(now);
    bfs3(n);
    for(int i=1;i<=n;++i){			/// 见公式
        int zuo = dis2[i]-1;
        int you = (dis3[i]+1-1)/2;
        int zuo2 = dis2[fa2[i]] -1;
        int you2 = (dis3[fa2[i]]+1-1)/2;
        if(zuo<=you && zuo2<you2)ans = max(you,ans);
    }
    printf("%d",ans);
    return 0;
}

你可能感兴趣的:(【2020牛客多校九:树的BFS】K :The Flee Plan of Groundhog)