Regular Forestation

Regular Forestation

时间限制: 1 Sec 内存限制: 128 MB

题目描述

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 N N nodes connected by N − 1 N−1 N1 edges. Let u u u be a node in a tree U U U which degree is at least 2 2 2 (i.e. directly connected to at least 2 2 2 other nodes in U U U). If we remove u u u from U U 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 ) V(S) V(S) be the set of nodes in a tree S S S and V ( T ) V(T) V(T) be the set of nodes in a tree T T T. Tree S S S and tree T T T are identical if there exists a bijection f : V ( S ) → V ( T ) f:V(S)→V(T) f:V(S)V(T) such that for all pairs of nodes ( s i , s j ) (s_i,s_j) (si,sj) in V ( S ) V(S) V(S), s i s_i si and s j s_j sj is connected by an edge in S S S if and only if node f ( s i ) f(s_i) f(si) and f ( s j ) f(s_j) f(sj) is connected by an edge in T T T. Note that f ( s ) = t f(s)=t f(s)=t implies node s s s in S S S corresponds to node t t t in T T 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 U U, your task is to determine whether there exists a good cutting point in U U 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 13 13 nodes.

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

The bijection function between A and B: f ( 5 ) = 8 , f ( 1 ) = 2 , f ( 7 ) = 11 f(5)=8, f(1)=2, f(7)=11 f(5)=8,f(1)=2,f(7)=11, and f ( 13 ) = 6 f(13)=6 f(13)=6.
The bijection function between A and C: f ( 5 ) = 3 , f ( 1 ) = 12 f(5)=3, f(1)=12 f(5)=3,f(1)=12, f ( 7 ) = 9 f(7)=9 f(7)=9, and f ( 13 ) = 10 f(13)=10 f(13)=10.
The bijection function between B and C: f ( 8 ) = 3 , f ( 2 ) = 12 f(8)=3, f(2)=12 f(8)=3,f(2)=12, f ( 11 ) = 9 f(11)=9 f(11)=9, and f ( 6 ) = 10 f(6)=10 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 ) N (3≤N≤4000) N(3N4000) representing the number of nodes in the given tree. The next N − 1 N−1 N1 lines each contains two integers: a i b i ( 1 ≤ a i < b i ≤ N ) a_i b_i (1≤a_i<b_i≤N) aibi(1ai<biN) representing an edge ( a i , b i ) (a_i,b_i) (ai,bi) in the given tree. It is guaranteed that any two nodes in the given tree are connected to each other by a sequence of edges.

输出

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

思路

容易想到,能够删去的点不可能存在多个,而且删去的必然是树的重心。剩下就是个判树同构了,而这个可以直接对树进行哈希来判断。

/***  Amber  ***/
#pragma GCC optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
using namespace std;
#define ls (rt<<1)
#define rs (rt<<1|1)
typedef long long ll;
typedef pair<int,int> pii;
template <typename T>
inline void read(T &x) {
    x = 0;
    static int p;
    p = 1;
    static char c;
    c = getchar();
    while (!isdigit(c)) {
        if (c == '-')p = -1;
        c = getchar();
    }
    while (isdigit(c)) {
        x = (x << 1) + (x << 3) + (c - 48);
        c = getchar();
    }
    x *= p;
}
template <typename T>
inline void print(T x) {
    if (x<0) {
        x = -x;
        putchar('-');
    }
    static int cnt;
    static int a[50];
    cnt = 0;
    do {
        a[++cnt] = x % 10;
        x /= 10;
    } while (x);
    for (int i = cnt; i >= 1; i--)putchar(a[i] + '0');
    puts("");
}
const double Pi=acos(-1);
const double eps=1e-6;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
const ll Inf = 0x3f3f3f3f3f3f3f3f;
const int maxn = 4010;

struct node{
    int v,nxt;
}e[maxn << 1];
int head[maxn],t;
int n;
int siz[maxn];
inline void add(int u,int v) {
    t++;
    e[t].v = v;
    e[t].nxt = head[u];
    head[u] = t;
}
void getsz(int u,int fa) {
    siz[u] = 1;
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].v;
        if (v == fa) continue;
        getsz(v, u);
        siz[u] += siz[v];
    }
}
int rt;
int getrt(int u,int fa) {
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].v;
        if (v == fa) continue;
        if (siz[v] > n / 2) return getrt(v, u);
    }
    return u;
}
int a[maxn];
int tot;
void getp(ll u,ll fa) {
    a[++tot] = u;
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].v;
        if (v == fa) continue;
        getp(v, u);
    }
}
ll Hash(int u,int fa) {
    vector<int> q;
    int ans = maxn;
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].v;
        if (v != fa && v != rt) {
            q.push_back(Hash(v, u));
        }
    }
    sort(q.begin(), q.end());
    for (int i = 0; i < q.size(); i++) {
        ans = (ans * 19260817 + q[i]) % mod;
    }
    return (ans * 19260817 + maxn + 1) % mod;
}
ll ans[maxn][maxn];
inline void work() {
    read(n);
    for (int i = 1; i < n; i++) {
        int u, v;
        read(u);
        read(v);
        add(u, v);
        add(v, u);
    }
    getsz(1, 0);
    rt = getrt(1, 0);
    getsz(rt, 0);
    ll cnt = 0;
    for (ll i = head[rt]; i; i = e[i].nxt) {
        cnt++;
        int v = e[i].v;
        tot = 0;
        getp(v, rt);
        for (int j = 1; j <= tot; j++) {
            ans[cnt][j] = Hash(a[j], 0);
        }
        sort(ans[cnt] + 1, ans[cnt] + tot + 1);
        if (cnt == 1) continue;
        int k = 0, flag = 0;
        while (k <= tot) {
            if (ans[cnt][++k] != ans[1][k]) {
                flag = 1;
                break;
            }
        }
        if (flag) {
            puts("-1");
            return;
        }
    }
    printf("%lld\n", cnt);
}
int main() {
    //freopen("1.txt","r",stdin);
    int T = 1;
    //read(T);
    while (T--) {
        work();
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值