Andrew and Chemistry
Description
During the chemistry lesson Andrew learned that the saturated hydrocarbons (alkanes) enter into radical chlorination reaction. Andrew is a very curious boy, so he wondered how many different products of the reaction may be forms for a given alkane. He managed to solve the task for small molecules, but for large ones he faced some difficulties and asks you to help.
Formally, you are given a tree consisting of nn vertices, such that the degree of each vertex doesn't exceed 44 . You have to count the number of distinct non-isomorphic trees that can be obtained by adding to this tree one new vertex and one new edge, such that the graph is still the tree and the degree of each vertex doesn't exceed 44 .
Two trees are isomorphic if there exists a bijection f(v)f(v) such that vertices uu and vv are connected by an edge if and only if vertices f(v)f(v) and f(u)f(u) are connected by an edge.
Input Format
The first line of the input contains an integer nn ( 1<=n<=1000001<=n<=100000 ) — the number of vertices in the tree.
Then follow n-1n−1 lines with edges descriptions. Each edge is given by two integers u_{i}ui and v_{i}vi ( 1<=u_{i},v_{i}<=n1<=ui,vi<=n ) — indices of vertices connected by an edge. It's guaranteed that the given graph is a tree and the degree of each vertex doesn't exceed 44 .
Output Format
Print one integer — the answer to the question.
Sample Input
4
1 2
2 3
2 4
Sample Output
2
解析
题目大意:给你一个有\(n\)个点的树。当每一个点的度不超过\(4\)时这棵树是合法的。现在让你再添加一个点,在树仍然合法的情况下,一共有多少种树。当两棵树同构时视作同一种。
思路就是枚举,枚举每一个原来度数小于\(4\)的点作为加点的点,然后只要看以该点为根时这棵树是否与之前的方案同构即可。
同构就是用树哈希判,这里的方法类似于记忆化搜索:设\(f[x][fa]\)代表以\(fa\)为\(x\)的父亲时,子树\(x\)的\(hash\)值。当这个状态没有\(hash\)值的时候,我们就取其子节点的所有\(hash\)值放在一个集合里做一次映射,得到一个正整数权值,当做\(hash\)值即可。
显然这样可以保证正确性:叶节点构造的集合都是空集,其映射的正整数也是相同的,当两棵树同构的时候,对应节点也都会因为相同的集合映射出相同的\(hash\)值,那这样树的权值也就是相同的。
而记忆化搜索就帮助我们保证了效率,当然,开不下的数组可以用\(map\),因为我们知道状态总数是不超空间的:一条边只对应了一个状态。
\(Code:\)
#include <bits/stdc++.h> using namespace std; const int N = 100020; int n , cnt; vector < int > e[N]; map < int , int > f[N]; map < vector<int> , int > List; set < int > S; inline int dp(int x,int fa) { if ( f[x].count(fa) ) return f[x][fa]; vector < int > temp; for ( int i = 0; i < e[x].size(); i++ ) { int y = e[x][i]; if ( y == fa ) continue; temp.push_back( dp( y , x ) ); } sort( temp.begin() , temp.end() ); if ( !List.count( temp ) ) List[ temp ] = ++cnt; return f[x][fa] = List[ temp ]; } int main(void) { scanf("%d",&n); for ( int i = 1; i < n; i++ ) { int u , v; scanf("%d%d",&u,&v); e[u].push_back( v ); e[v].push_back( u ); } for ( int i = 1; i <= n; i++ ) if ( e[i].size() < 4 ) S.insert( dp( i , 0 ) ); printf("%d\n",S.size()); return 0; }