【Codeforces】2015-2016 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2015) A Adjoin the Netwo
程序员文章站
2022-07-15 16:10:13
...
题目链接:http://codeforces.com/gym/100781/attachments
题目大意:给你n个点和l条边, 让你添加一些边形成一棵树使得树的直径尽可能小。
(1 <= n <= 1e5) (0 <= l <= n - 1)
解题思路:我们先把已经形成的一些树的每个直径都求出来, 把这些直径从大到小排序, 如果只有1个直径, 答案就是这个直径, 如果有两个, 就是最长和次长从中间连起来, 还有一种可能就是第三长和第二长连起来比第一第二长。 求树的直径, 我用的是一遍dfs, dfs 的时候维护当前节点为根的最长和次长值, 最后 根节点最长+次长就是直径。
//2017-08-01 22:13
//2017-08-01 22:29
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cstdlib>
#include<vector>
using namespace std;
const int MaxN = 1e5;
int n, m, len;
vector<int>edge[MaxN + 5];
int q[MaxN + 5];
bool vis[MaxN + 5];
bool cmp(int a, int b){ return a > b; }
int dfs(int u){
vis[u] = true;
int m1 = 0, m2 = 0;
for(int i = 0; i < edge[u].size(); i++){
int v = edge[u][i];
if(!vis[v]){
int tmp = dfs(v) + 1;
if(tmp > m1){m2 = m1, m1= tmp;}
else if(tmp > m2){m2 = tmp;}
}
}
len = max(len, m1 + m2);
return m1;
}
int main(){
scanf("%d %d", &n, &m);
for(int i = 1; i <= m; i++){
int u, v;
scanf("%d %d", &u, &v);
edge[u].push_back(v);
edge[v].push_back(u);
}
int cnt = 0, ans = 0;
for(int i = 0; i < n; i++){
len = 0;
if(!vis[i]){
int tmp = dfs(i);
q[++cnt] = len;
ans = max(ans, len);
}
}
sort(q + 1, q + 1 + cnt, cmp);
if(cnt > 1) ans = max(ans, (q[1] + 1) / 2 + (q[2] + 1) / 2 + 1);
if(cnt > 2) ans = max(ans, (q[2] + 1) / 2 + (q[3] + 1) / 2 + 2);
printf("%d\n", ans);
return 0;
}