Codeforces 1182D Complete Mirror 树的重心乱搞 / 树的直径 / 拓扑排序

题意:给你一颗树,问这颗树是否存在一个根,使得对于任意两点,如果它们到根的距离相同,那么它们的度必须相等。

思路1:树的重心乱搞

根据样例发现,树的重心可能是答案,所以我们可以先判断一下树的重心可不可以。如果不行,剩下的只可能是度为1点当根了。当然,我们不能枚举所有度为1的点,不然一个菊花图就超时了,我的做法是对于以重心为根的树搜索一遍,对于每个深度的度数为1的点只记录一个,然后枚举这些点,如果有就是有,否则没有。这样最坏的复杂度应该能到O(n * sqrt(n)),但是肯定跑不满。至于为什么这样做,因为感觉每个深度如果有多个点,要么随便选一个都可以,要么都不可以。没想到场上就这样过了,希望评论区有大佬的话能出个hack数据。。。

代码:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define db double
#define LL long long
#define pii pair<int, int>
using namespace std;
const int maxn = 100010;
vector<int> G[maxn];
void add(int x, int y) {
	G[x].push_back(y);
	G[y].push_back(x);
}
bool flag = 0;
bool v[maxn];
int sz[maxn], n, re[maxn];
int ans = INF, root;
map<int, int> mp;
map<int, int> ::iterator it;
void dfs(int x) {
	v[x] = 1;
	sz[x] = 1;
	int max_part = 0;
	for (auto y : G[x]) {
		if(v[y]) continue;
		dfs(y);
		sz[x] += sz[y];
		max_part = max(max_part, sz[y]);
	}
	max_part = max(max_part, n - sz[x]);
	if(max_part < ans) {
		ans = max_part;
		root = x;
	}
}
void dfs1(int x, int fa, int deep) {
	if(re[deep] == 0) {
		re[deep] = G[x].size();
	} else {
		if(re[deep] != G[x].size()) {
			flag = 1;
		//	return;
		}
	}
	sz[x] = 1;
	for (auto y : G[x]) {
		if(y == fa) continue;
		dfs1(y, x, deep + 1);
		//if(flag == 1) return;
		sz[x] += sz[y];
	}
	if(G[x].size() == 1) {
		mp[deep] = x;
	}
}
bool solve() {
	flag = 0;
	memset(re, 0, sizeof(re));
	for (auto y : G[root]) {
		dfs1(y, root, 1);
	}
	int now = 0;
	for (auto y : G[root]) {
		if(now == 0) now = sz[y];
		else {
			if(now != sz[y]) {
				flag = 1;
				return flag;
			}
		}
	}
	return flag;
}
int main() {
	int x, y;
	scanf("%d", &n);
	for (int i = 1; i < n; i++) {
		scanf("%d%d", &x, &y);
		add(x, y);
	}
	dfs(1);
	if(!solve()) {
		printf("%d\n", root);
		return 0;
	}
	else {
		for (it = mp.begin(); it != mp.end(); it++) {
			root = it -> second;
			if(!solve()) {
				printf("%d\n", root);
				return 0;
			}
		}
	}
	printf("-1\n");
} 

 思路2:(官方题解)跑一遍树的直径,先判断直径两端行不行,如果不行,从直径的中点开始,找不经过直径上的边可以到达的度数为1的点,判断行不行。

 代码就咕了

   思路3:(官方题解)跑一遍拓扑排序,直到只剩一个点,然后找到这个点最近的和最远的度数为1的点,判断行不行。

   代码也咕了

  思路2和思路3只能直观感受上好像是对的QAQ, 不会证,场上想不出来这种思路,只能乱搞水一水了QAQ 。

  结合官方题解的图应该更好理解思路2和思路3:

  官方题解:https://codeforces.com/blog/entry/67614

posted @ 2019-06-12 21:49  维和战艇机  阅读(595)  评论(0编辑  收藏  举报