无根树同构_hash
先贴上地址 https://vjudge.net/problem/HDU-5732
判断有根树同构:
1. 直接用括号最小表示法
2. 利用括号最小表示法的思想进行hash
判断无根树同构:
1. 找到树的重心.
2. 以重心为根, 把无根树转化成有根树. 按照有根树同构的方法判断是否同构.
同构的过程中,为什么可以sort.
我们知道,对于树来说,
树的节点绕着它的父节点旋转,树的结构就不会被改变的.
所以sort的过程就相当于把树的节点绕着它的父节点进行旋转.
// sort的话,可以这么理解:
我们是按照同样的规则(我们保证这个规则可以唯一确定一棵树,),
对两棵树进行操作,如果同构的话,那么结果应该是一样的. 如果不同构的画 那么结果就是不一样的
至于树的括号表达式, 可以见这几个博客
括号表达式 https://www.byvoid.com/zhs/blog/directed-tree-bracket-sequence
树同构 https://blog.csdn.net/u010152669/article/details/9116975
树的表示方法 https://www.cnblogs.com/jsawz/p/6807636.html
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector> using namespace std; typedef unsigned long long ull;
const int maxn = 1e5+;
ull x[maxn];
int ans[maxn]; struct Edge {
int lst;
int to;
}; class Tree {
public :
Edge edge[maxn<<];
int head[maxn];
int cn, csz, ccnt, mid[];
int rcd[maxn];
ull cnode[maxn];
ull vvvvv[];
map<string, int> id;
char name[maxn][]; inline void add(int u, int v) {
edge[csz].lst = head[u];
edge[csz].to = v;
head[u] = csz++;
} int dfs(int u, int fa) {
int i, v, res = , t1;
for (i=head[u]; i; i=edge[i].lst) {
v = edge[i].to;
if (v == fa) continue;
t1 = dfs(v, u);
res += t1;
if (rcd[u] < t1) rcd[u] = t1;
if (rcd[v] < cn-t1) rcd[v] = cn-t1;
}
return res + ;
} ull dfs2(int u, int fa, int deep) {
int i, v, res = , t1;
vector<ull> son;
for (i=head[u]; i; i=edge[i].lst) {
v = edge[i].to;
if (v == fa) continue;
son.push_back(dfs2(v, u, deep+));
}
sort(son.begin(), son.end()); // 判断树同构 注意要sort后乘一个随机数(或者一个质数的i次方). 为什么可以sort呢? 因为树同一层的节点围绕父节点旋转不会改变树的结构. 而sort相当于把节点绕父节点旋转了.
for (i=, t1=son.size(); i<t1; ++i)
res += son[i] * x[i+];
return cnode[u] = (res ? res : x[deep]);
} void init(int n) {
cn = n; csz = ; id.clear();
int i, u, v, cnt = ;
char s1[], s2[]; for (i=; i<=n; ++i) rcd[i] = head[i] = ; for (i=; i<n; ++i) {
scanf("%s%s", s1, s2);
if (!(u = id[s1])) {
strcpy(name[cnt], s1);
id[s1] = u = cnt++;
} if (!(v = id[s2])) {
strcpy(name[cnt], s2);
id[s2] = v = cnt++;
}
add(u, v); add(v, u);
} dfs(, -);
int mm = 0x3f3f3f3f;
for (i=; i<=n; ++i) {
if (mm > rcd[i]) {
mm = rcd[i];
ccnt = ;
mid[++ccnt] = i;
} else if (mm == rcd[i]) mid[++ccnt] = i;
} for (i=; i<=ccnt; ++i)
vvvvv[i] = dfs2(mid[i], -, );
}
}te1, te2; struct nobe {
int id;
ull val;
bool operator < (const nobe &a) const {
return val < a.val;
}
nobe () {}
nobe (int iid, ull vval) : id(iid), val(vval) {}
}; void dfs3(int u1, int u2, int fa1, int fa2) {
int i, v1, v2, tsz;
ans[u1] = u2;
vector<nobe> ve1, ve2;
for (i=te1.head[u1]; i; i=te1.edge[i].lst) {
v1 = te1.edge[i].to;
if (v1 == fa1) continue;
ve1.push_back(nobe(v1, te1.cnode[v1]));
}
for (i=te2.head[u2]; i; i=te2.edge[i].lst) {
v2 = te2.edge[i].to;
if (v2 == fa2) continue;
ve2.push_back(nobe(v2, te2.cnode[v2]));
}
sort(ve1.begin(), ve1.end());
sort(ve2.begin(), ve2.end());
for (i=, tsz=ve1.size(); i<tsz; ++i)
dfs3(ve1[i].id, ve2[i].id, u1, u2);
} int main()
{
int i, j, k, n;
srand(time(NULL));
for (i=; i<maxn; ++i) x[i] = rand();
while (~scanf("%d", &n)) {
te1.init(n);
te2.init(n);
for (i=; i<=te1.ccnt; ++i)
for (j=; j<=te2.ccnt; ++j) {
if (te1.vvvvv[i] == te2.vvvvv[j]) {
dfs3(te1.mid[i], te2.mid[j], te1.mid[i], te2.mid[j]);
for (k=; k<=n; ++k)
printf("%s %s\n", te1.name[k], te2.name[ans[k]]);
goto A;
}
}
A: ;
} return ;
}
无根树同构_hash的更多相关文章
- 3194. 【HNOI模拟题】化学(无标号无根树计数)
Problem 求\(n\)个点的每个点度数不超过\(4\)的无标号无根树个数. Data constraint \(1\le n\le 500\) Solution 尝试着把问题一般化.我们来考虑一 ...
- BZOJ 4754 [JSOI2016]独特的树叶 | 树哈希判同构
题目链接 这道题是一道判断无根树同构的模板题,判断同构主要的思路就是哈希. 一遇到哈希题,一百个人能有一百零一种哈希方式,这篇题解随便选用了一种--类似杨弋<Hash在信息学竞赛中的一类应用&g ...
- 【CF1252F】Regular Forestation(重心,树同构)
题意:给定一棵n个点的树,问删去某个点之后所有的树同构,这样分割出来的树最多能有几棵 n<=4000 思路:分割成至少两个size相等的联通块之后size必定小于n/2,与树的重心的定义相同 预 ...
- 【BZOJ4337】树的同构(树同构,哈希)
题意: 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树. 对于两个树T1和T2,如果能够把树T1T ...
- ustc 1117
无根树同构 有两种方法,一种是确定其中一棵树,另一棵树枚举根节点. 一种是,利用拓扑排序,先确定其中一棵树.另一棵树,若拓扑后剩两个节点,则枚举这两个节点为根结点,否则,只需做一次.注意,无根树节点入 ...
- 树hash
判断树的同构,采用树hash的方式. 树hash定义在有根树上.判断无根树同构的时候,可以比较重心为根的hash值或者比较每个点为根的hash值. h[x]表示x为根的子树的hash,g[x]表示x为 ...
- uva12489 Combating cancer(树同构)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud https://uva.onlinejudge.org/index.php?opt ...
- 4337: BJOI2015 树的同构
题解: 树的同构的判定 有根树从根开始进行树hash 先把儿子的f进行排序 $f[i]=\sum_{j=1}^{k} { f[j]*prime[j]} +num[i]$(我没有仔细想这样是不是树是唯一 ...
- [BJOI2015]树的同构
嘟嘟嘟 判断树的同构的方法就是树上哈希. 如果树是一棵有根树,那么只要从根节点出发dfs,每一个节点的哈希值等于按传统方式算出来的子树的哈希值的结果.需要注意的是,算完子树的哈希值后要先排序再加起来, ...
随机推荐
- 《高性能SQL调优精要与案例解析》新书样章
该书样章已上传,需要的同学可以通过如下地址下载:http://www.itpub.net/thread-2091839-1-1.html http://www.itpub.net/thread-209 ...
- Python爬虫原理
前言 简单来说互联网是由一个个站点和网络设备组成的大网,我们通过浏览器访问站点,站点把HTML.JS.CSS代码返回给浏览器,这些代码经过浏览器解析.渲染,将丰富多彩的网页呈现我们眼前: 一.爬虫是什 ...
- C#实体对象序列化成Json并让字段的首字母小写的两种解决方法
引言:最近在工作中遇到与某些API对接的post的数据需要将对象的字段首字母小写.解决办法有两种:第一种:使用对象的字段属性设置JsonProperty来实现(不推荐,因为需要手动的修改每个字段的属性 ...
- Qt Widgets——动作类与小部件菜单项
本文主要涉及以下三个类: QAction ——QWidgetAction QActionGroup QAction可称为动作类,它一般可当作菜单中的项组成菜单,也可作为工具栏上的按钮,它主要由图标.文 ...
- 给div添加锚点
<div class="col-xs-3" id="myScrollspy"> <ul class="nav nav-tabs na ...
- suffix word ard ar arian arium atic ation atory ator out ~3
1★ ard 不好的人 2★ ar ~的:~人物 1● arian ~人.物 2● arium 地点,场地 3●aster 不怎么样的人 1● ast ~人 ...
- 初学Linux系统最应该做对的4件事情[长文]
“闲来无事,逛逛贴吧”已经是本人无事消磨时间的最佳选择了.五花八门的问题,各式各样的回答,总能给自己带来无限的欢乐.当然也有些问题值得自己去思考或者回答.之前就有人在贴吧里问到“Linux好难啊!该怎 ...
- 首席科学家马丁•福勒(Martin Fowler)
现任思特沃克公司首席科学家的马丁·福勒先生是当今世界软件开发领域最具影响力的五位大师之一.作为一位敏捷软件开发方法的早期开拓者,福勒先生对IT 业的影响是不可估量的. 思特沃克公司是一家跨国专业IT ...
- pyhton 学习 函数式编程
函数是python内建支持的一种封装,我们通过把打断的代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计,函数就是面向过程的程序设计的基本单元 ...
- post请求返回 读取 HTML 表单 URL 编码的数据流时出错
<httpRuntime maxRequestLength="1048576" executionTimeout="3600" /> 网站配置 限制 ...