http://codeforces.com/gym/100781/attachments
题意:有N个点,M条边,问对两两之间的树添加一条边之后,让整棵大树最远的点对之间的距离最近,问这个最近距离是多少。
思路:一开始看成只有两个连通块,后来才注意到是多个连通块。DFS搜树上最长路径。答案有三种:第一种是添加了边之后,树的最长路径还是原来子树的路径,第二种是对子树长度进行排序后,两个最长的距离分别除以2向上取整后加上1。第三种比较难注意到,就是第二第三长的分别除以2向上取整后加上2,因为可能隔着一条边之后比第一种情况更长了。
1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <string> 6 #include <cmath> 7 #include <queue> 8 #include <vector> 9 using namespace std; 10 #define N 100010 11 struct node 12 { 13 int v, nxt; 14 }edge[N*2]; 15 int head[N], tot; 16 bool vis[N]; 17 int ans[N]; 18 int l; 19 20 void add(int u, int v) 21 { 22 edge[tot].v = v; edge[tot].nxt = head[u]; head[u] = tot++; 23 } 24 25 bool cmp(const int &a, const int &b) 26 { 27 return a > b; 28 } 29 30 int dfs(int u) 31 { 32 vis[u] = 1; 33 int m1 = 0, m2 = 0; 34 for(int i = head[u]; ~i; i = edge[i].nxt) { 35 int v = edge[i].v; 36 if(vis[v]) continue; 37 int tmp = dfs(v) + 1; 38 if(tmp > m1) { 39 m2 = m1, m1 = tmp; 40 } else if(tmp > m2) { 41 m2 = tmp; 42 } 43 } 44 if((m1 + m2) > l) l = m1 + m2; 45 return m1; 46 } 47 48 int main() 49 { 50 int n, m; 51 scanf("%d%d", &n, &m); 52 memset(vis, 0, sizeof(vis)); 53 memset(head, -1, sizeof(head)); 54 memset(ans, 0, sizeof(ans)); 55 tot = 0; 56 for(int i = 0; i < m; i++) { 57 int u, v; 58 scanf("%d%d", &u, &v); 59 add(u, v); add(v, u); 60 } 61 int cnt = 0, res = 0; 62 for(int i = 0; i < n; i++) { 63 if(!vis[i]) { 64 l = 0; 65 dfs(i); //搜树上最长路径 66 if(l > res) res = l; //第一种情况 67 ans[cnt++] = l; 68 } 69 } 70 sort(ans, ans + cnt, cmp); 71 if(cnt > 1) res = max(res, (ans[0] + 1) / 2 + (ans[1] + 1) / 2 + 1); //第二种情况 72 if(cnt > 2) res = max(res, (ans[1] + 1) / 2 + (ans[2] + 1) / 2 + 2); //第三种情况 73 printf("%d\n", res); 74 return 0; 75 }
时间: 2024-10-25 04:37:43