『Andrew and Chemistry 树同构』
<更新提示>
<第一次更新>
<正文>
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
解析#
题目大意:给你一个有nn个点的树。当每一个点的度不超过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;
}
<后记>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】博客园2025新款「AI繁忙」系列T恤上架,前往周边小店选购
【推荐】凌霞软件回馈社区,携手博客园推出1Panel与Halo联合会员
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 解锁.NET 9性能优化黑科技:从内存管理到Web性能的最全指南
· 通过一个DEMO理解MCP(模型上下文协议)的生命周期
· MySQL下200GB大表备份,利用传输表空间解决停服发版表备份问题
· 记一次 .NET某固高运动卡测试 卡慢分析
· 微服务架构学习与思考:微服务拆分的原则
· AI浏览器自动化实战
· Chat to MySQL 最佳实践:MCP Server 服务调用
· 解锁.NET 9性能优化黑科技:从内存管理到Web性能的最全指南
· .NET周刊【3月第5期 2025-03-30】
· 重生之我是操作系统(八)----文件管理(上)