Regular Forestation(树的重心 + 树哈希)

题目描述
A forestation is an act of planting a bunch of trees to grow a forest, usually to replace a forest that had been cut down. Strangely enough, graph theorists have another idea on how to make a forest, i.e. by cutting down a tree!

A tree is a graph of N nodes connected by N−1 edges. Let u be a node in a tree U which degree is at least 2 (i.e. directly connected to at least 2 other nodes in U). If we remove u from U, then we will get two or more disconnected (smaller) trees, or also known as forest by graph theorists. In this problem, we are going to investigate a special forestation of a tree done by graph theorists.

Let V(S) be the set of nodes in a tree S and V(T) be the set of nodes in a tree T. Tree S and tree T are identical if there exists a bijection f:V(S)→V(T) such that for all pairs of nodes (si,sj) in V(S), si and sj is connected by an edge in S if and only if node f(si) and f(sj) is connected by an edge in T. Note that f(s)=t implies node s in S corresponds to node t in T.

We call a node u in a tree U as a good cutting point if and only if the removal of u from U causes two or more disconnected trees, and all those disconnected trees are pairwise identical.

Given a tree U, your task is to determine whether there exists a good cutting point in U. If there is such a node, then you should output the maximum number of disconnected trees that can be obtained by removing exactly one good cutting point.

For example, consider the following tree of 13 nodes.

There is exactly one good cutting point in this tree, i.e. node 4. Observe that by removing node 4, we will get three identical trees (in this case, line graphs), i.e. {5,1,7,13}, {8,2,11,6}, and {3,12,9,10}, which are denoted by A, B, and C respectively in the figure.

The bijection function between A and B: f(5)=8, f(1)=2, f(7)=11, and f(13)=6.
The bijection function between A and C: f(5)=3, f(1)=12, f(7)=9, and f(13)=10.
The bijection function between B and C: f(8)=3, f(2)=12, f(11)=9, and f(6)=10.
Of course, there exists other bijection functions for those trees.

输入
Input begins with a line containting an integer: N (3≤N≤4000) representing the number of nodes in the given tree. The next N−1 lines each contains two integers: ai bi (1≤ai

输出
Output in a line an integer representing the maximum number of disconnected trees that can be obtained by removing exactly one good cutting point, or output -1 if there is no such good cutting point.

样例输入
【样例1】
13
1 5
1 7
2 4
2 8
2 11
3 12
4 7
4 12
6 11
7 13
9 10
9 12
【样例2】
6
1 2
1 3
2 4
3 5
3 6

样例输出
【样例1】
3
【样例2】
-1

思路
先寻找树的重心,对树的重心,根据子树的哈希判断是否同构

代码实现

#pragma GCC optimize(3, "Ofast", "inline")
#include 
#define re register
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 4005;
const int M = 1000005;
const int INF = 0x3f3f3f3f;
const ll LINF = 1e18;
const ull sed = 19260817;
const ll mod = 998244353;
const double eps = 1e-6;
const double PI = acos(-1.0);
const double delta = 0.993;
typedef pair<int, int> P;
typedef pair<double, double> Pd;
typedef pair<ll, int> plt;
typedef pair<ll, ll> pll;

template <class T>
inline void read(T &x)
{
     
    x = 0;
    int f = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
     
        f |= (ch == '-');                                   
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
     
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    x = f ? -x : x;
    return;
}

template <class T>
inline void write(T x)
{
     
    if (x < 0)
        x = ~x + 1, putchar('-');
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}

vector<int>E[N];
int siz[N],n;
int rt,num;

void getsz(int u,int fa)
{
     
    siz[u]=1;
    for(auto v:E[u])
    {
     
        if(v==fa) continue;
        getsz(v,u);
        siz[u]+=siz[v];
    }
}

int getrt(int u,int fa)
{
     
    for(auto v:E[u])
    {
     
        if(v==fa) continue;
        if(siz[v]>n/2) return getrt(v,u);
    }
    return u;
}

int a[N],tot;
ll Hash[N][N];

void dfs(int u,int fa)
{
     
    a[++tot]=u;
    for(auto v:E[u])
    {
     
        if(v==fa) continue;
        dfs(v,u);
    }
}

ll Tree_hash(int u,int fa)
{
     
    vector<ll>h;
    ll ans=N;
    for(auto v:E[u]) if(v!=fa && v!=rt) h.push_back(Tree_hash(v,u));
    sort(h.begin(),h.end());
    for(auto v:h) ans=(ans*sed+v)%mod;
    return (ans*sed+N+1)%mod;
}

bool judge()
{
     
    for(auto v:E[rt])
    {
     
        num++;
        tot=0;
        dfs(v,rt);
        for(int i=1;i<=tot;i++) Hash[num][i]=Tree_hash(a[i],0);
        sort(Hash[num]+1,Hash[num]+1+tot);
        if(num==1) continue;
        int k=0;
        while (k<=tot) if(Hash[num][++k]!=Hash[1][k]) break;
        if(k<=tot) return false;
    }
    return true;
}

int main()
{
     
#ifndef ONLINE_JUDGE
    freopen("a.txt","r",stdin);
#endif
    // freopen("10.in","w",stdout);
    read(n);
    for(int i=1;i<n;i++)
    {
     
        int u,v;
        read(u);read(v);
        E[u].push_back(v);
        E[v].push_back(u);
    }
    getsz(1,0);
    rt=getrt(1,0);
    getsz(rt,0);
    if(judge()) printf("%d\n",num);
    else puts("-1");
    return 0;
}

你可能感兴趣的:(#,树的重心,#,树哈希,树)