题意: 判断一棵树是否为斐波那契树。判定条件:
- 树中的节点数量为斐波那契数。
- 切断某条边,可拆成两棵斐波那契树 || 树中只有一个节点
题解: 判断一棵树是不是斐波那契树,要看它是否能拆成两棵斐波那契树,而那两棵拆分出来的也需要通过相同的手段去进行判定。直至节点数量为1,就可以判断是一棵斐波那契树。
拆什么边其实是没有讲究的,因为理论上需要逐步拆成n棵节点数为1的树,所以每条边都是需要拆的。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int n;
int sz[maxn];
int fib[maxn];
vector<int> vec;
int cnt, head[maxn];
struct edge { int v, flag, next; } e[maxn << 1];
void add (int u, int v) {
e[++cnt] = {v, 0, head[u]}; head[u] = cnt;
e[++cnt] = {u, 0, head[v]}; head[v] = cnt;
}
void dfs (int u, int fa) {
sz[u] = 1;
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].v;
if (v == fa) continue;
if (e[i].flag) continue;
dfs(v, u);
sz[u] += sz[v];
vec.push_back(i);
}
}
int check (int u, int size) {
if (size <= 3) return 1;
if (!fib[size]) return 0;
vec.clear();
dfs(u, 0);
for (int i : vec) {
int v = e[i].v;
if (fib[sz[v]] && fib[size - sz[v]]) {
e[i].flag = 1;
e[i + ((i & 1) ? 1 : -1)].flag = 1;
return check(u, size - sz[v]) && check(v, sz[v]);
}
}
return 0;
}
void init () {
int fir = 1, sec = 1;
while (1) {
fib[sec] = 1;
if (sec >= n) break;
int sum = fir + sec;
fir = sec,sec = sum;
}
}
int main () {
scanf("%d", &n);
for (int i = 1, u, v; i < n; ++i) {
scanf("%d%d", &u, &v);
add(u, v);
}
init();
if (check(1, n)) printf("YES");
else printf("NO");
return 0;
}