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

题目链接: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_第1张图片

//2017-08-01 22:13
//2017-08-01 22:29
#include
#include
#include
#include
#include
#include
using namespace std;
const int MaxN = 1e5;

int n, m, len;
vectoredge[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;
}



你可能感兴趣的:(CodeForces,DFS,树的直径)