题目链接:http://codeforces.com/problemset/problem/813/C
题意:给出一颗树,开始时两个人 Alice 和 Bob 分别站在 1(树根)和 x 处.此后每一次操作两人都可以选择在原地不动或者移动到相邻的节点(Bob先移动);
直至两人移到同一个位置,两人移动的总步数为 ans,Alice要使 ans 尽量小,Bob 要使 ans 尽量大,输出ans;
思路:假设最终在 p 位置相遇,显然 p 是由先移动的 Bob 决定的,即 p 能使 ans 最大;
用 dis1[p] 表示 1 到 p 的距离,dis2[p] 表示 x 到 p 的距离,要满足 Alice 和 Bob 在移动到 p 之前不相遇,所以有 dis1[p] > dis2[p],那么显然有 ans = 2 * dis1[p];
即:先 bfs 出 1 和 x 到其他节点的最短距离,再遍历所有节点,对于节点 i,若满足 dis1[i] > dis2[i] ,则 ans = max(ans, 2 * dis1[i]),最终输出 ans 即可;
代码:
1 #include <iostream> 2 #include <stdio.h> 3 #include <vector> 4 #include <queue> 5 #include <string.h> 6 using namespace std; 7 8 const int MAXN = 2e5 + 10; 9 vector<int> mp[MAXN]; 10 bool vis[MAXN]; 11 12 13 void bfs(int dis[MAXN], int p){//求以 p 为根时其余个点到 p 的距离 14 memset(vis, 0, sizeof(vis)); 15 int ans = 0, cnt1 = 1, cnt2 = 0; 16 queue<int> q; 17 q.push(p); 18 vis[p] = true; 19 while(!q.empty()){ 20 while(cnt1--){ 21 int cnt = q.front(); 22 q.pop(); 23 for(int i = 0; i < mp[cnt].size(); i++){ 24 int cc = mp[cnt][i]; 25 if(!vis[cc]){ 26 q.push(mp[cnt][i]); 27 vis[mp[cnt][i]] = true; 28 cnt2++; 29 } 30 } 31 dis[cnt] = ans; 32 } 33 cnt1 = cnt2; 34 cnt2 = 0; 35 ans++; 36 } 37 } 38 39 int main(void){ 40 int n, x; 41 scanf("%d%d", &n, &x); 42 for(int i = 0; i < n - 1; i++){ 43 int s, e; 44 scanf("%d%d", &s, &e); 45 mp[s].push_back(e); 46 mp[e].push_back(s); 47 } 48 int dis1[MAXN], dis2[MAXN]; 49 bfs(dis1, 1); 50 bfs(dis2, x); 51 int ans = 0; 52 for(int i = 1; i <= n; i++){ 53 if(dis1[i] > dis2[i] && mp[i].size() == 1){ 54 ans = max(ans, dis1[i]*2); 55 } 56 } 57 cout << ans << endl; 58 return 0; 59 }