【bzoj4337】【BJOI2015】【树的同构】【hash】

2024-02-20 15:08
文章标签 同构 hash bzoj4337 bjoi2015

本文主要是介绍【bzoj4337】【BJOI2015】【树的同构】【hash】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Description

树是一种很常见的数据结构。
我们把N个点,N-1条边的连通无向图称为树。
若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树。
对于两个树T1和T2,如果能够把树T1的所有点重新标号,使得树T1和树T2完全相
同,那么这两个树是同构的。也就是说,它们具有相同的形态。
现在,给你M个有根树,请你把它们按同构关系分成若干个等价类。

Input

第一行,一个整数M。
接下来M行,每行包含若干个整数,表示一个树。第一个整数N表示点数。接下来N
个整数,依次表示编号为1到N的每个点的父亲结点的编号。根节点父亲结点编号为0。

Output

输出M行,每行一个整数,表示与每个树同构的树的最小编号。

Sample Input

4
4 0 1 1 2
4 2 0 2 3
4 0 1 1 1
4 0 1 2 3

Sample Output

1
1
3
1

HINT

【样例解释】 

编号为1, 2, 4 的树是同构的。编号为3 的树只与它自身同构。 

100% 的数据中,1 ≤ N, M ≤ 50。 

题解:

         从每个点开始将这棵树hash一遍然后判断即可.

         我采用的hash方法是

            hash[x]=sigma(hash[st[i]]*p[i+1])+p[1] st[i]代表x的第i棵子树,p是一个素数表.

         注意这些子树需要按hash值排序.

代码:

         

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define N 110
#define M 3000
#define ui unsigned int
using namespace std;
int n,m,x,point[N],next[M<<1],cnt;
unsigned int hash[N][N],f[N];
unsigned int p[]={0,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,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317};
struct use{int st,en;
}e[M<<1];
int read(){int x(0);char ch=getchar();while (ch<'0'||ch>'9') ch=getchar();while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return x; 
}
void add(int x,int y){next[++cnt]=point[x];point[x]=cnt;e[cnt].st=x;e[cnt].en=y;
}
void dfs(int x,int fa){int top=0;unsigned int st[N];st[++top]=1;for (int i=point[x];i;i=next[i])if (e[i].en!=fa){dfs(e[i].en,x);st[++top]=f[e[i].en];}sort(st+1,st+top+1);f[x]=0;for (int i=1;i<=top;i++) f[x]+=st[i]*p[i]; 
}
int main(){//freopen("a.in","r",stdin);m=read();for (int i=1;i<=m;i++){n=read();memset(point,0,sizeof(point));for (int j=1;j<=n;j++){x=read();if (x) add(x,j),add(j,x);}for (int j=1;j<=n;j++){dfs(j,0);hash[i][j]=f[j];// cout<<j<<' '<<f[j]<<endl;}sort(hash[i]+1,hash[i]+n+1);//for (int j=1;j<=n;j++) cout<<hash[i][j]<<' ';//cout<<endl;for (int j=1;j<=i;j++){int k;for (k=1;k<=n;k++)if (hash[j][k]!=hash[i][k]) break;if (k>n) {printf("%d\n",j);break;}}} 
}


这篇关于【bzoj4337】【BJOI2015】【树的同构】【hash】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/728620

相关文章

Redis的Hash类型及相关命令小结

《Redis的Hash类型及相关命令小结》edisHash是一种数据结构,用于存储字段和值的映射关系,本文就来介绍一下Redis的Hash类型及相关命令小结,具有一定的参考价值,感兴趣的可以了解一下... 目录HSETHGETHEXISTSHDELHKEYSHVALSHGETALLHMGETHLENHSET

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

hdu1496(用hash思想统计数目)

作为一个刚学hash的孩子,感觉这道题目很不错,灵活的运用的数组的下标。 解题步骤:如果用常规方法解,那么时间复杂度为O(n^4),肯定会超时,然后参考了网上的解题方法,将等式分成两个部分,a*x1^2+b*x2^2和c*x3^2+d*x4^2, 各自作为数组的下标,如果两部分相加为0,则满足等式; 代码如下: #include<iostream>#include<algorithm

usaco 1.2 Milking Cows(类hash表)

第一种思路被卡了时间 到第二种思路的时候就觉得第一种思路太坑爹了 代码又长又臭还超时!! 第一种思路:我不知道为什么最后一组数据会被卡 超时超了0.2s左右 大概想法是 快排加一个遍历 先将开始时间按升序排好 然后开始遍历比较 1 若 下一个开始beg[i] 小于 tem_end 则说明本组数据与上组数据是在连续的一个区间 取max( ed[i],tem_end ) 2 反之 这个

uva 10029 HASH + DP

题意: 给一个字典,里面有好多单词。单词可以由增加、删除、变换,变成另一个单词,问能变换的最长单词长度。 解析: HASH+dp 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc

整数Hash散列总结

方法:    step1  :线性探测  step2 散列   当 h(k)位置已经存储有元素的时候,依次探查(h(k)+i) mod S, i=1,2,3…,直到找到空的存储单元为止。其中,S为 数组长度。 HDU 1496   a*x1^2+b*x2^2+c*x3^2+d*x4^2=0 。 x在 [-100,100] 解的个数  const int MaxN = 3000

POJ 1198 双广+Hash

此题采用双广可从bfs的O(16^8)降低到O(2*16^4); 坐标0-7,刚好3位存储, 需要24位存储四个坐标(x,y),也就是[0,2^24) 。 很好的一题。 import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import

C# Hash算法之MD5、SHA

MD5我们用的还是比较多的,一般用来加密存储密码。但是现在很多人觉MD5可能不太安全了,所以都用上了SHA256等来做加密(虽然我觉得都差不多,MD5还是能玩)。 还是跟上一篇说的一样,当一个算法的复杂度提高的同时肯定会带来效率的降低,所以SHA和MD5比较起来的话,SHA更安全,MD5更高效。 由于HASH算法的不可逆性,所以我认为MD5和SHA主要还是应用在字符串的"加密"上。 由于