欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【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 的时候维护当前节点为根的最长和次长值, 最后 根节点最长+次长就是直径。


【Codeforces】2015-2016 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2015) A Adjoin the Netwo

//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;
}