BZOJ 4337 树的同构

很明显,这应该是一道模版题(因为我很快就在一本书上找到了这道题的模版),不过令我比较奇怪的大概是有根树和无根树的概念,以及在这道题目中根有卵用吗? (看来树这一块的知识还是要补一下)。 树的同构很明显应该是用hash来判断的,当然了,不同的人设计的hash函数不同了。这道题正确的应该是要在树的重心上面跑这道题的模版,(如果你要问我树的重心是啥,我只能跟你说,如果我知道的话,下面这份代码就不会把几乎所有的点都跑一次了,但是由于N<=50,M <= 50 很明显这样跑完还是很快的,事实证明也只跑了32毫秒,但本着求真务实的心态,找个时间再补下树吧!)。很明显,尽管两棵树的形态完全相同,但如果从不同的节点开始跑这个模版,所得的hash值也会不同。所以正确的是要在几乎唯一的重心上跑(据说,一棵有根树的重心最多有两个)。加油吧!相信自己。(我是一条可耻的源程狗)。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<vector>
  4 #include<set>
  5 #include<map>
  6 #include<algorithm>
  7 #define ull unsigned long long
  8 #define magic 107ull
  9 #define rep(i,j,k) for(int i = j; i <= k; i++)
 10 #define maxn 60
 11 using namespace std;
 12
 13 int read()
 14 {
 15     int s = 0, t = 1; char c = getchar();
 16     while( !isdigit(c) ){
 17         if( c == ‘-‘ ) t = -1; c = getchar();
 18     }
 19     while( isdigit(c) ){
 20         s = s * 10 + c -‘0‘; c = getchar();
 21     }
 22     return s * t;
 23 }
 24
 25 ull pow(ull key,int n)
 26 {
 27     ull ret = 1ull;
 28     while( n ){
 29        if( n & 1 ){
 30              ret *= key;
 31        }
 32        key *= key, n >>= 1;
 33     }
 34     return ret;
 35 }
 36
 37 struct hash{
 38 int length; ull key;
 39
 40 hash(): length(0), key(0) {}
 41 hash(char c): length(1), key(c) {}
 42 hash(int l,ull key): length(l), key(key) {}
 43 };
 44 vector<hash> childs[maxn];
 45
 46 bool operator < (const hash&a, const hash&b){
 47     return a.key < b.key;
 48 }
 49
 50 hash operator + (const hash&a, const hash& b){
 51     return hash(a.length+b.length,a.key*pow(magic,b.length)+b.key);
 52 }
 53
 54 void operator += (hash&a,const hash&b){
 55     a = a + b;
 56 }
 57
 58 vector<int> g[maxn];
 59
 60 hash dfs(int pre,int now)
 61 {
 62     hash ret;
 63     childs[now].clear(); int s = g[now].size();
 64     rep(i,0,s-1){
 65         int to = g[now][i];
 66         if( to == pre ) continue;
 67         childs[now].push_back(dfs(now,to));
 68     }
 69     sort(childs[now].begin(),childs[now].end());
 70     for(vector<hash>::iterator iter = childs[now].begin(); iter != childs[now].end(); iter++){
 71         ret += *iter;
 72     }
 73     ret = ‘(‘ +  ret + ‘)‘;
 74     return ret;
 75
 76 }
 77
 78 ull gethash(int root)
 79 {
 80     return dfs(-1,root).key;
 81 }
 82
 83 set<ull> s;
 84 map<ull,int> mp;
 85
 86 void clear()
 87 {
 88     rep(i,1,maxn) g[i].clear();
 89 }
 90
 91 int main()
 92 {
 93     int n = read();
 94     rep(i,1,n){
 95         clear(); s.clear();
 96         int m = read();
 97         rep(j,1,m){
 98             int x = read();
 99             if( x ) g[j].push_back(x), g[x].push_back(j);
100         }
101         bool ok = 0;
102         rep(j,1,m){
103             ull key = gethash(j);
104             if( mp[key] ) {
105                 printf("%d\n", mp[key]);
106                 ok = 1;
107                 break;
108             }
109             else s.insert(key);
110         }
111         if( !ok ){
112             printf("%d\n", i);
113             for(set<ull>::iterator iter = s.begin(); iter != s.end(); iter++ ){
114                 mp[*iter] = i;
115             }
116         }
117     }
118     return 0;
119 }
时间: 2024-11-10 04:20:42

BZOJ 4337 树的同构的相关文章

4337. [BJOI2015]树的同构【树哈希】

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

[BZOJ4337][BJOI2015]树的同构(树的最小表示法)

4337: BJOI2015 树的同构 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1023  Solved: 436[Submit][Status][Discuss] Description 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树. 对于两个树T1和T2,如果能够把树T1的所有点重新标号,使得树T1和树T2完全相 同,那么这两个树是同

SDUT 3340 数据结构实验之二叉树一:树的同构

数据结构实验之二叉树一:树的同构 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Description 给定两棵树T1和T2.如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是"同构"的.例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A.B.G的左右孩子互换后,就得到另外一棵树.而图2就不是同构的. 图1 图2 现给定两棵树,请你判断它们是否是同构的. Input 输入数据包含

03-树1 树的同构

给定两棵树T1和T2.如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是“同构”的.例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A.B.G的左右孩子互换后,就得到另外一棵树.而图2就不是同构的. 图1 图2 现给定两棵树,请你判断它们是否是同构的. 输入格式: 输入给出2棵二叉树树的信息.对于每棵树,首先在一行中给出一个非负整数NN (\le 10≤10),即该树的结点数(此时假设结点从0到N-1N−1编号):随后NN行,第ii行对应编号第ii个结点,给出该结点中存储的

5-3 树的同构 (25分)

5-3 树的同构   (25分) 给定两棵树T1和T2.如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是"同构"的.例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A.B.G的左右孩子互换后,就得到另外一棵树.而图2就不是同构的. 图1 图2 现给定两棵树,请你判断它们是否是同构的. 输入格式: 输入给出2棵二叉树树的信息.对于每棵树,首先在一行中给出一个非负整数NN (\le 10≤10),即该树的结点数(此时假设结点从0到N-1N?1编号):随后NN行,第i

ZOJ--3602--Count the Trees【DFS+Hash】树的同构

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3602 题意:给出一棵有n个节点的二叉树和一棵有m个节点的二叉树,给出每个节点的左右子树信息,问这两棵树有几个相同的子树. 思路:树的同构,比赛时没想法,赛后看的别人的解题报告.实际上是给每个节点的左右子树一个哈希值,不用像字符串哈希那么麻烦,直接给每个子树一个数字标记就行了,用map映射每个节点的左子树和右子树信息对应一个标记值,用DFS给两棵树的每个节点都赋一个哈

bzoj 3083 树链剖分

首先我们先将树提出一个根变成有根树,那么我们可以通过树链剖分来实现对于子树的最小值求解,那么按照当前的根和询问的点的相对位置关系我们可以将询问变成某个子树和或者除去某颗子树之后其余的和,前者直接询问区间,后者询问区间的补集. /************************************************************** Problem: 3083 User: BLADEVIL Language: C++ Result: Accepted Time:6412 ms

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

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <stdbool.h> 5 6 typedef char ElemType; 7 8 typedef struct BinTree 9 { 10 ElemType data; 11 struct BinTree *left; 12 struct BinTree *right; 13 }BinTree; 14

PTA 树的同构(25 分)

7-1 树的同构(25 分) 给定两棵树T1和T2.如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是"同构"的.例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A.B.G的左右孩子互换后,就得到另外一棵树.而图2就不是同构的. 图1 图2 现给定两棵树,请你判断它们是否是同构的. 输入格式: 输入给出2棵二叉树树的信息.对于每棵树,首先在一行中给出一个非负整数N (≤10),即该树的结点数(此时假设结点从0到N?1编号):随后N行,第i行对应编号第i个结点,给出