[CF1491E] Fib-tree

[CF1491E] Fib-tree - 分治,树

Description

现在给你一棵包含了 (n) 个结点的树。我们称一棵树为 Fib-tree,要求其结点树为某一个 (F_k),且满足以下至少一个:树仅包含一个结点;从某条边划开,形成的两棵子树都是 Fib-tree。请判断给出的树是不是 Fib-tree。

Solution

如果是个 Fib-tree,那么一定可以切成一个 n-1-Fib-tree 和一个 n-2-Fib-tree

有时候可以有多种切法,但是可以归纳证明,只要是 Fib-tree,无论哪一种切法都是可行的

假设有两条边 e1,e2,都是可行的,我们切 e1,那么 e2 一定在那个 n-1-Fib-tree 内,可以参与下一次切割

因此,能切就切,分治求解

#include <bits/stdc++.h>
using namespace std;
 
const int N = 1000005;
 
set<int> g[N];
int n;
int siz[N];
int fib[N],fid[N],fa[N];
vector<int> vec;
 
void dfs(int p,int from)
{
    siz[p]=1;
    vec.push_back(p);
    for(int q:g[p]) if(q!=from)
    {
        dfs(q,p);
        fa[q]=p;
        siz[p]+=siz[q];
    }
}
 
bool check(int p,int size)
{
    if(size<=3) return true;
    vec.clear();
    dfs(p,0);
    int size_id=fid[size];
    int tar_size=fib[size_id-1];
    int res_p=0,res_q=0,psize=0;
    for(int i:vec)
    {
        if(siz[i]==tar_size || size-siz[i]==tar_size)
        {
            res_p=i;
            res_q=fa[i];
            psize=siz[p];
            break;
        }
    }
    if(res_p)
    {
        g[res_p].erase(res_q);
        g[res_q].erase(res_p);
        return check(res_p,psize) && check(res_q,size-psize);
    }
    else 
    {
        return false;
    }
}
 
signed main()
{
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    fib[0]=fib[1]=1;
    for(int i=2;i<=30;i++) fib[i]=fib[i-1]+fib[i-2];
    for(int i=1;i<=30;i++) fid[fib[i]]=i;
    for (int i = 1; i < n; i++)
    {
        int t1, t2;
        cin >> t1 >> t2;
        g[t1].insert(t2);
        g[t2].insert(t1);
    }
    if (check(1,n))
    {
        cout << "YES" << endl;
    }
    else
    {
        cout << "NO" << endl;
    }
}
原文地址:https://www.cnblogs.com/mollnn/p/14473024.html