题目链接:点击查看
题目大意:给出 m 棵树,对于第 i 棵树而言,找到 1 ~ i 中与当前树同构的最小 id
题目分析:判断有向树同构,可以预处理出质数数组 p ,然后树形 dp ,设 u 为当前节点,v 为子节点,那么 dp[ u ] += dp[ v ] * p[ sz[ v ] ] ,dp 数组设置为 unsigned long long,让他自然溢出即可,而无根树判断同构,只需要以无根树的重心为根节点,再进行上面有向树判断同构的过程即可,因为每棵树的重心至多有两个,所以都要一起保存下来
最后提一句和 zx 学长闲聊时提到的,我问为什么他的代码要让 p 数组随机打乱一下,zx 学长说有题目可能会卡树上哈希,也就是会卡连续的质数,所以打乱一下基本上就构造不出可以卡掉的数据了
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=60;
int p[]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229};
vector<int>node[N];
vector<ull>Hash[N];
ull f[N];
int rt1,rt2,sz[N],wt[N],n;
void get_root(int u,int fa)
{
sz[u]=1;
wt[u]=0;
for(auto v:node[u])
{
if(v==fa)
continue;
get_root(v,u);
sz[u]+=sz[v];
wt[u]=max(wt[u],sz[v]);
}
wt[u]=max(wt[u],n-sz[u]);
if(rt1==0||wt[rt1]>wt[u])
rt1=u,rt2=0;
else if(wt[rt1]==wt[u])
rt2=u;
}
void dfs(int u,int fa)
{
f[u]=sz[u]=1;
for(auto v:node[u])
{
if(v==fa)
continue;
dfs(v,u);
f[u]+=f[v]*p[sz[v]];
sz[u]+=sz[v];
}
}
void init(int n)
{
rt1=rt2=0;
for(int i=1;i<=n;i++)
node[i].clear();
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
random_shuffle(p+1,p+1+50);
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d",&n);
init(n);
for(int j=1;j<=n;j++)
{
int fa;
scanf("%d",&fa);
if(fa)
{
node[fa].push_back(j);
node[j].push_back(fa);
}
}
get_root(1,-1);
if(rt1)
{
dfs(rt1,-1);
Hash[i].push_back(f[rt1]);
}
if(rt2)
{
dfs(rt2,-1);
Hash[i].push_back(f[rt2]);
}
if(Hash[i].size()==1)//填个0
Hash[i].push_back(0);
if(Hash[i][0]>Hash[i][1])//排序
swap(Hash[i][0],Hash[i][1]);
}
for(int i=1;i<=m;i++)
for(int j=1;j<=i;j++)
if(Hash[i][0]==Hash[j][0]&&Hash[i][1]==Hash[j][1])
{
printf("%d\n",j);
break;
}
return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/35508.html