题意:给你一颗树,问这颗树是否存在一个根,使得对于任意两点,如果它们到根的距离相同,那么它们的度必须相等。
思路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 ", root); return 0; } else { for (it = mp.begin(); it != mp.end(); it++) { root = it -> second; if(!solve()) { printf("%d ", root); return 0; } } } printf("-1 "); }
思路2:(官方题解)跑一遍树的直径,先判断直径两端行不行,如果不行,从直径的中点开始,找不经过直径上的边可以到达的度数为1的点,判断行不行。
代码就咕了
思路3:(官方题解)跑一遍拓扑排序,直到只剩一个点,然后找到这个点最近的和最远的度数为1的点,判断行不行。
代码也咕了
思路2和思路3只能直观感受上好像是对的QAQ, 不会证,场上想不出来这种思路,只能乱搞水一水了QAQ 。
结合官方题解的图应该更好理解思路2和思路3: