题意:一个无向树的度数为 2的结点称为假结点,其它结点称为真结点。一个无向树的简化树
其结点由原树的全体真结点组成,两个真结点之间有边当且仅当它们在原树中有边,或者在
原树中有一条联结这两个结点的路,其中间节点全是假结点。两个无向树各自的简化树如果
同构,即存在结点之间的一一对应,使得在一个树中的任意两个结点之间有边当且仅当它们
的对应结点在另一个树中有边,则称原来的两个无向树实质同构。给定若干个无向树,将相
互实质同构的无向树只保留一个其余删除。统计剩下的相互不实质同构的无向树个数,并将
它们的简化树结点个数从小到大输出。

cas<=20 n<=10000

思路:把很久以前在另一个地方写的题解搬过来

定义题。做法请看题目。

删除假节点并连边:先按输入构图并统计每个点的度数 找一个度不为2的点做一遍dfs

if d[v]=2 f[find(u)]=f[find(v)]

做完之后重连所有f[x[i]]<>f[y[i]]的边

同构:

哈希,将点上的哈希初值都=1,对于点u,取与u相连的点权V并排序,随意哈希作为新的哈希值。迭代10000000000000000000000000000000次。最后只需判断哈希值是否相等。

 const mo=;
var head,vet,next,d,b,x,y,e1,q,f:array[..]of longint;
hash,s,c,h:array[..]of int64;
cas,v1,e,v,i,tot,len,n,j,k,ans:longint;
tmp:int64;
p:boolean; procedure qsort(l,r:longint);
var i,j:longint;
t,mid:int64;
begin
i:=l; j:=r; mid:=q[(l+r)>>];
repeat
while mid>q[i] do inc(i);
while mid<q[j] do dec(j);
if i<=j then
begin
t:=q[i]; q[i]:=q[j]; q[j]:=t;
inc(i); dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end; function find(k:longint):longint;
begin
if f[k]<>k then f[k]:=find(f[k]);
find:=f[k];
end; procedure add(a,b:longint);
begin
inc(tot);
next[tot]:=head[a];
vet[tot]:=b;
head[a]:=tot;
end; procedure dfs(u,fa:longint);
var e,v:longint;
begin
e:=head[u];
while e<> do
begin
v:=vet[e];
if v<>fa then
begin
if d[v]= then f[find(v)]:=f[find(u)];
dfs(v,u);
end;
e:=next[e];
end;
end; begin readln(cas); for v1:= to cas do
begin
read(n);
fillchar(head,sizeof(head),);
fillchar(b,sizeof(b),);
fillchar(d,sizeof(d),);
for i:= to n do hash[i]:=;
for i:= to n do f[i]:=i;
tot:=;
for i:= to n- do
begin
read(x[i],y[i]);
inc(d[x[i]]); inc(d[y[i]]);
add(x[i],y[i]);
add(y[i],x[i]);
end;
for i:= to n do
if d[i]<> then
begin
dfs(i,-);
break;
end;
tot:=;
fillchar(head,sizeof(head),); for i:= to n- do
if f[x[i]]<>f[y[i]] then
begin
b[f[x[i]]]:=; b[f[y[i]]]:=;
add(f[x[i]],f[y[i]]);
add(f[y[i]],f[x[i]]);
end;
for i:= to n do
if d[i]<> then inc(e1[v1]);
for i:= to do
begin
for j:= to n do h[j]:=hash[j];
for j:= to n do
if b[j]= then
begin
e:=head[j];
len:=;
while e<> do
begin
v:=vet[e];
inc(len); q[len]:=h[v];
e:=next[e];
end;
if len> then qsort(,len);
tmp:=;
for k:= to len do tmp:=(tmp*+q[k]) mod mo;
hash[j]:=tmp; end;
end;
len:=;
for i:= to n do
if b[i]= then begin inc(len); q[len]:=hash[i]; end;
if len> then qsort(,len);
tmp:=;
for i:= to len do tmp:=(tmp*+q[i]) mod mo; s[v1]:=tmp;
end;
for i:= to cas do
begin
p:=true;
for j:= to i- do
if s[i]=s[j] then
begin
p:=false; break;
end;
if p then begin inc(ans); c[ans]:=e1[i]; end;
end;
for i:= to ans do q[i]:=c[i];
qsort(,ans);
writeln(ans);
for i:= to ans- do write(q[i],' ');
write(q[ans]); end.

【BZOJ4474】isomorphism(树的同构,哈希)的更多相关文章

  1. bzoj4337: BJOI2015 树的同构 树哈希判同构

    题目链接 bzoj4337: BJOI2015 树的同构 题解 树哈希的一种方法 对于每各节点的哈希值为hash[x] = hash[sonk[x]] * p[k]; p为素数表 代码 #includ ...

  2. 【BZOJ4337】树的同构(树同构,哈希)

    题意: 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树. 对于两个树T1和T2,如果能够把树T1T ...

  3. [BJOI2015]树的同构

    嘟嘟嘟 判断树的同构的方法就是树上哈希. 如果树是一棵有根树,那么只要从根节点出发dfs,每一个节点的哈希值等于按传统方式算出来的子树的哈希值的结果.需要注意的是,算完子树的哈希值后要先排序再加起来, ...

  4. bzoj4337树的同构

    树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树. 对于两个树T1和T2,如果能够把树T1的所有点重 ...

  5. BZOJ4337:[BJOI2015]树的同构(树hash)

    Description 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树. 对于两个树T1和T2,如 ...

  6. BZOJ4337:[BJOI2015]树的同构——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4337 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根, ...

  7. Andrew and Chemistry(树的同构)

    Andrew and Chemistry(树的同构) 题链 将一棵树转化为最小表示法,将此时的树哈希一下,同时用map进行标记,就可以判断树是否存在同构 #include <map> #i ...

  8. 【PTA】浙江大学数据结构慕课 课后编程作业 03-树1 树的同构

    题目内容 给定两棵树T1和T2.如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是"同构"的.例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A.B.G的左右 ...

  9. 03-树1 树的同构 (C语言链表实现)

    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h& ...

随机推荐

  1. C#菜鸟正则表达式一

    LZ菜鸟,仅整理笔记,顺带记录一下,谓之增加印象. LZ认为,没必要太纠结原理,模型, 屌丝能用就对了,剩下的事情用多了自然会去探索. 中文:正则表达式,英文:Regular  ExPression, ...

  2. Sqlmap脱库之“你的数据我所见”

    废话不多说,介绍和理论啥的网上一搜一大把,一次只为tuoku. 实战操作: 1.在网上找个index.php?id=1的站点 2.很明显看到了脱下裤子的希望,sqlmap走一把.查看数据库 3.怎么看 ...

  3. BaseAdapter的优化

    传统的 package cct.commonadapter.bean; import android.content.Context; import android.view.LayoutInflat ...

  4. 迅为iMX6UL开发板低功耗高能效开发平台

    迅为i.MX 6UL开发板基于ARM Cortex-A7内核,主频高达528 MHz,内存:512MDDR3,存储:8G EMMC,支持2路CAN,2路百兆以太网,4路USB HOST,8路串口,以及 ...

  5. python学习(day2)

    1.常用数据类型及内置方法 1.列表(list) 定义:在中括号[]内存放任意多个值,用逗号隔开. 具体函数和内置方法如下: #定义学生列表,可存放多个学生 students=['a','b','c' ...

  6. 几个net命令

    A.显示当前工作组服务器列表 net view,当不带选项使用本命令时,它就会显示当前域或网络上的计算机上的列表.  比如:查看这个IP上的共享资源,就可以  C:\\>net view 192 ...

  7. python连接mysql的操作

    一,安装mysql 如果是windows 用户,mysql 的安装非常简单,直接下载安装文件,双击安装文件一步一步进行操作即可. Linux 下的安装可能会更加简单,除了下载安装包进行安装外,一般的l ...

  8. Linux内核中TCP SACK机制远程DoS预警通告

    漏洞描述 2019年6月18日,RedHat官网发布报告:安全研究人员在Linux内核处理TCP SACK数据包模块中发现了三个漏洞,CVE编号为CVE-2019-11477.CVE-2019-114 ...

  9. VC++线程函数内怎么调用外部函数

    VC++线程函数内怎么调用外部函数 1.把外部函数做成静态函数,就可以直接调用了.2.把外部函数所在的对象通过线程函数参数传到线程里面来,这样线程里可以使用此对象及其函数了.

  10. vc中无符号字符数组保存的内存值转换为无符号整数保存

    分为三步,第一步,将进行指针类型转换:第二步,进行*地址运算:第三部赋值. 贴代码如下: unsigned char numberPlain [4] = {0}; UINT32 MaxNumber = ...