一、题目描述:
给你一颗
使得
注意,这里是有根树,旋转树之后的同构不算同构。输出
数据范围:
二、解题思路:
树同构,本能地想到树哈希。而树哈希推荐
容易发现,若一棵子树不与
所以我们只需要找到最小的一颗子树使得它不与
发现这颗最小的子树一定会很小,因为
所以我们直接从小到大枚举子树就行。设这颗子树的大小为
那么这颗子树最大有多大呢?考虑
注意到一颗多叉树唯一对应一颗二叉树(分左右儿子),而一颗二叉树也唯一对应一颗多叉树。
又注意到一颗二叉树唯一对应一颗完全二叉树,一颗完全二叉树唯一对应一颗二叉树。
所以就是求一颗
考虑怎么不重不漏的枚举树的形态。暴搜枚举每一个点的父亲节点。
但是这样很明显会枚举到很多同构的树,时间复杂度变为
其实只需要做一个小剪枝就可以了,就是枚举的父亲节点顺序单调不降。
想一下就想明白了,就像那个什么最小表示法一样。于是时间复杂度
三、完整代码:
1 #include<bits/stdc++.h> 2 #define V e[i].v 3 #define N 1000010 4 #define rep(i,l,r) for(int i=l;i<=r;i++) 5 using namespace std; 6 map <int,bool> mp; 7 mt19937 m(time(0)); 8 int n,mask,ha[N],fa[N]; 9 struct EDGE{ 10 int v,nxt; 11 }e[N<<1]; 12 int head[N],cnt; 13 void add(int u,int v){ 14 e[++cnt].v=v; 15 e[cnt].nxt=head[u]; 16 head[u]=cnt; 17 } 18 int shift(int val){ 19 val^=mask; 20 val^=val<<13; 21 val^=val>>7; 22 val^=val<<17; 23 val^=mask; 24 return val; 25 } 26 void dfs(int u,int ff){ 27 ha[u]=1; for(int i=head[u];i!=-1;i=e[i].nxt) 28 if(V!=ff) dfs(V,u),ha[u]+=ha[V]; 29 ha[u]=shift(ha[u]); 30 } 31 void dfs2(int step,int lim,int num){ 32 if(step>num){ 33 rep(i,1,num) head[i]=-1; cnt=0; 34 rep(i,2,num) add(fa[i],i); dfs(1,0); 35 if(!mp[ha[1]]){ 36 int k=n-num; 37 rep(i,1,k) cout<<i<<" "<<i+1<<'\n'; 38 rep(i,2,num) cout<<i+k<<" "<<fa[i]+k<<'\n'; 39 exit(0); 40 } return ; 41 } 42 rep(i,lim,step-1) fa[step]=i,dfs2(step+1,i,num); 43 } 44 int main(){ 45 ios::sync_with_stdio(false); 46 cin.tie(0);cout.tie(0); 47 cin>>n; mask=m(); 48 rep(i,1,n) head[i]=-1; 49 rep(i,1,n-1){ 50 int u,v; cin>>u>>v; 51 add(u,v); add(v,u); 52 } 53 dfs(1,0); rep(i,1,n) mp[ha[i]]=1; 54 rep(i,1,n) dfs2(2,1,i); 55 rep(i,2,n) cout<<i-1<<" "<<i<<'\n'; 56 return 0; 57 }
四、写题心得:
好,第二次写树哈希,收获经验如下:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探