Codefroces Gym 100781A(树上最长路径)

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 }

 

转载于:https://www.cnblogs.com/fightfordream/p/5901085.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值