题解【[BJOI2015]树的同构】
切了省选题+紫题,来写个题解
这题其实挺水,才120行代码
该题写了我一天(上午1.5h,晚上10min = 一天)
hash,对于节点A,$$hashval[A] = {hashval[i]\times2333^{num} | i \in son[A] }$$ , 并且hashval[i]大于任何在他前面加的数,num为目前加到第几个
写成代码就是
function Hash(int n){
vector V ;
for_each(i in son[n]) do
HV[i] = Hash(i) ;
V.pushback(HV[i]) ;
V.sort()
for_each(i in V)
HV[n] = HV[n]*2333+HV[i] ;
return HV[n]*2333+1002 ;
//HV[i]初值为1
}
那么对于树中的每个节点做一遍Hash,时间复杂度为$$O(N \times (N+NlogN+N))$$
所以总的的时间复杂度为$$O(M \times N \times NlogN) == O(N^3logN)$$
说人话:$$O(\text{能过})$$
Talk is free , show me the code
#include<iostream>
#include<vector>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std ;
inline void read(int &x) {
char ch=getchar();
int s=0,f=1;
while (!(ch>='0'&&ch<='9')) {
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9') {
s=(s<<3)+(s<<1)+ch-'0';
ch=getchar();
}
x=s*f;
}
class TREE{
private:
vector<int> son[55] ;
int hashval[55] ;
int H[55] ;
bool inq[55] ;
int size[55] ;
int root ;
int n ;
int check(vector<int> N){
int S = N.size() ;
for(int j:N) {
if(inq[j]) --S ;
}
return S ;
}
public:
//这个MIAOMIAOMIAO函数就是Hash啦喵~
int MIAOMIAOMIAO(int n,int f){
inq[n] = true ;
vector<int> V ;
for(const int & i : son[n]){
if(i==f) continue ;
//cout<<"dfs in dot "<<i<<endl ;
hashval[i] = MIAOMIAOMIAO(i,n) ;
//cout<<"HashVal["<<i<<"] = "<<hashval[i]<<endl ;
V.push_back(hashval[i]) ;
//cout<<"HashVal["<<n<<"] = "<<hashval[n]<<endl ;
}
sort(V.begin(),V.end()) ;
for(const int& i : V)
hashval[n] = hashval[n]*2333 + i ;
//hashval[n] = 2333*hashval[n] + 1001 ;
return hashval[n]*2333+1002 ;
}
void getsize(int n,int f){
inq[n] = true ;
if(!check(son[n])) size[n] = 1 ;
for(int i:son[n]){
if(i!=f) getsize(i,n) ;
size[n] += size[i] ;
}
}
bool comp(const int& a,const int& b){
return a>b ;
}
int sZ() {return this->n ;}
void init(){
read(n) ;
for(int i=1;i<=n;++i){
int x ;
read(x) ;
if(x==0) { root=i ; continue ; }
son[x].push_back(i) , son[i].push_back(x) ;
}
//cout<<"Root = "<<root<<endl ;
getsize(root,root) ;
memset(inq,0,sizeof(inq)) ;
for(int i=1;i<=n;++i){
sort(son[i].begin() , son[i].end() , [this](int a, int b) -> bool { return size[a] < size[b]; }) ;
}
for(int j=1;j<=n;++j) hashval[j] = 1 ;
for(int i=1;i<=n;++i){
MIAOMIAOMIAO(i,i) ;
H[i] = hashval[i] ;
memset(inq,0,sizeof(inq)) ;
for(int j=1;j<=n;++j) hashval[j] = 1 ;
}
//for(int i=1;i<=n;++i) cout<<H[i]<<" ";
//cout<<endl ;
}
int gethashval(int DI){
return H[DI] ;
}
} ;
TREE Index[55] ;
int m ;
int HVL[55] ;
int ans[55][55] ;
int main(){
read(m) ;
for(int i=1;i<=m;++i){
//cout<<"TREE "<<i<<endl ;
Index[i].init() ;
HVL[i] = i ;
int n = Index[i].sZ() ;
for(int j=1;j<=n;++j){
ans[i][j] = Index[i].gethashval(j) ;
}
sort(ans[i]+1,ans[i]+n+1) ;
for(int j=1;j<=i;++j){
int k = 0 ;
while(k<=n)
if(ans[i][++k]!=ans[j][k])
break ;
if(k>n) { HVL[i] = j ; break ; }
}
}
for(int i=1;i<=m;++i) {
printf("%d\n",HVL[i]) ;
}
}
Oh对了
本代码使用C++11标准并对每棵树封装
提交时注意~~(我不会告诉你我因为这个WA了一次喵)~
还有说下那个for
for(const int& i : vector1) -> 对于每个vector1中的元素i,按vector1中的存放顺序访问
所以这个写起来省力~~(我不会告诉你还可以写for(auto& i:vector1)但是我忘了写喵)~
题解【[BJOI2015]树的同构】的更多相关文章
- BZOJ 4337: BJOI2015 树的同构 树hash
4337: BJOI2015 树的同构 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4337 Description 树是一种很常见的数 ...
- bzoj4337: BJOI2015 树的同构 树哈希判同构
题目链接 bzoj4337: BJOI2015 树的同构 题解 树哈希的一种方法 对于每各节点的哈希值为hash[x] = hash[sonk[x]] * p[k]; p为素数表 代码 #includ ...
- 【BZOJ4337】BJOI2015 树的同构 括号序列
[BZOJ4337]BJOI2015 树的同构 Description 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱 ...
- 4337: BJOI2015 树的同构
题解: 树的同构的判定 有根树从根开始进行树hash 先把儿子的f进行排序 $f[i]=\sum_{j=1}^{k} { f[j]*prime[j]} +num[i]$(我没有仔细想这样是不是树是唯一 ...
- [BZOJ4337][BJOI2015]树的同构(树的最小表示法)
4337: BJOI2015 树的同构 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1023 Solved: 436[Submit][Status ...
- BZOJ4337:[BJOI2015]树的同构——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4337 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根, ...
- [BJOI2015]树的同构
嘟嘟嘟 判断树的同构的方法就是树上哈希. 如果树是一棵有根树,那么只要从根节点出发dfs,每一个节点的哈希值等于按传统方式算出来的子树的哈希值的结果.需要注意的是,算完子树的哈希值后要先排序再加起来, ...
- BZOJ4337:[BJOI2015]树的同构(树hash)
Description 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树. 对于两个树T1和T2,如 ...
- 题解 P5043 【【模板】树同构([BJOI2015]树的同构)】
进入正题 题意:将所有树结构相同的树归类. 思路 嗯,这道题让我们把树的结构归类,自然而然就想到了哈希,我们对这整颗树哈希一遍.然后判同构就十分之简单了.只需要找哈希值一样的树就可以了. 其实真得很简 ...
随机推荐
- phpstudy后门复现(9.29第十五天)
本人转自:https://www.cnblogs.com/yuanshu/p/11613796.html 一.漏洞位置 程序自带的PHP的php_xmlrpc.dll模块中有隐藏后门,受影响的版本有p ...
- UVA - 1645 Count (统计有根树)(dp)
题意:输入n(n <=1000),统计有多少个n结点的有根树,使得每个深度中所有结点的子结点数相同.输出数目除以109+7的余数. 分析: 1.dp[i],i个结点的有根树个数 2.假设n=7, ...
- 通过整合遥感数据和社交媒体数据来进行城市土地利用的分类( Classifying urban land use by integrating remote sensing and social media data)DOI: 10.1080/13658816.2017.1324976 20.0204
Classifying urban land use by integrating remote sensing and social media data Xiaoping Liu, Jialv ...
- Android自定义View——刮刮卡效果
想要红包的实现效果的可以关注我的博客,仿饿了么红包 下层图片:我们的红包的图片 上层图片:有两部分 一部分是灰色背景 一部分是拥有透明度为0,并且模式为交集的画笔 使用滑动监听,滑动时,用透明度为0的 ...
- Codeforces 1296D - Fight with Monsters
题目大意: n 只怪兽,每只的血量为 h[i] ,你的攻击力为 a ,你的对手攻击力为 b 打每只怪兽时,都是你先出手,然后你的对手出手,这样轮流攻击 如果是你给予了怪兽最后一击,你就能得到一分 你还 ...
- redis常用命令--zsets
zsets常用命令: zadd key score1 mb1 [score2 mb2....]:像key中添加元素和这个元素的分数,如果元素已经存在,则替换分数. zscore key mb :获取k ...
- nginx常用内置变量
$args #请求中的参数值 $query_string #同 $args $arg_NAME #GET请求中NAME的值 $is_args #如果请求中有参数,值为"?",否则为 ...
- Nginx复习
Nginx基本概念 是什么,做什么事情 高性能的HTTP和反向代理web服务器,特点占有内存小,并发能力强, Nginx专为性能优化而开发,最高支持50000个并发连接数 反向代理 正向代理 在客户 ...
- MST(最小生成树)——Prim算法——HDU 1879-继续畅通工程
Prim算法很好理解,特别是学完了迪杰斯特拉算法之后,更加能理解Prim的算法思想 和迪杰斯特拉算法差不多,由于最后要形成连通图,故任意指定一个点,作为初始点,遍历所有点,以当前最小权值的点(和迪杰斯 ...
- SQL基础教程(第2版)第3章 聚合与排序:练习题
存在以下 个错误. .使用了字符类型的列(product_name)作为 SUM 函数的参数. >> 解答 SUM 函数只能使用数值类型的列作为参数. . WHERE 子句写在了 GROU ...