题意:
一个拥有 n n n 个点, n − 1 n-1 n−1 条边的无向联通图。现在有两个特殊点 u , v u,v u,v, u u u 想尽可能的远离 v v v,而 v v v 想尽可能的接近 u u u。
现有如下流程:
- 如果 u , v u,v u,v在一个节点上,那么结束。否则 u u u 可以移动到与当前节点相邻的任意一个其他节点。
- 如果 u , v u,v u,v在一个节点上,那么结束。否则 v v v 可以移动到与当前节点相邻的任意一个其他节点。
- 回到步骤1。
两个点均按最优解进行,请计算出结束前 v v v 所进行的操作数。
思路:
这道题的结论……我不好说,咱们还是直接看解法吧,差不多看完解法就懂做法了。
首先我们需要先把
u
,
v
u,v
u,v 两点到图上任意一点的最短距离求出来,设为
d
u
[
]
,
d
v
[
]
du[],dv[]
du[],dv[]。
那么如果
d
u
[
i
]
<
d
v
[
i
]
du[i]<dv[i]
du[i]<dv[i],那么
u
u
u 在到达该点时,以及在到达该点之前比不可能被抓到,这一点可以通过反证法轻松证得;
如果
d
u
[
i
]
=
=
d
v
[
i
]
du[i]==dv[i]
du[i]==dv[i],那么可能是在该点时被抓到的,也可能不是。也就是说如果到达该点,必定结束,但是我们所求的是结束前的最大操作数,所以无用;
如果
d
u
[
i
]
>
d
v
[
i
]
du[i]>dv[i]
du[i]>dv[i],不用多说,也必不可能是该点。
所以,综上所述,我们只需找到 d u [ i ] < d v [ i ] du[i]<dv[i] du[i]<dv[i] 时, d v [ ] dv[] dv[] 的最大值即可。
时间复杂度: O ( n ) O(n) O(n)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 10;
int n;
int e[N], ne[N], h[N], idx;
int l[N], r[N];
int st, ed;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void bfs(int fa, int u, int *d) {
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (j == fa)
continue;
d[j] = d[u] + 1;
bfs(u, j, d);
}
}
signed main() {
cin >> n >> st >> ed;
for (int i = 1; i <= n; i++)
h[i] = -1;
for (int i = 1, x, y; i < n; i++) {
scanf("%lld %lld", &x, &y);
add(x, y), add(y, x);
}
bfs(0, st, l), bfs(0, ed, r);
int res = 0;
for (int i = 1; i <= n; i++)
if (l[i] < r[i])
res = max(res, r[i]);
cout << res - 1;
return 0;
}