SDUT3926 kmp
bLue的二叉树
Time Limit: 3000MS Memory Limit: 65536KB
Problem Description
Keke 是一个喜爱种树的人,他对各种树都有很深的研究。
MLE 听说 bLue 种了一些新品种的树,就想邀请 Keke 去围观一下。
PBH 在暗中把这一切尽收眼底,作为资深植树行家,他虽不屑,但也决定和他们一起去看一看。
于是,大家便一起到了 bLue 家去看树。
bLue 有两棵二叉树,分别有 n 和 m 个节点,编号分别为 1-n 和 1-m,每个节点都有一个权值,bLue 想知道第一棵树的所有子树中与第二棵树完全相同的个数(不考虑节点编号)。
Input
输入数据有多组(数据组数不超过 150),到 EOF 结束。
对于每组数据:
- 第一行有两个整数 n (0 < n <= 10^5) 和 m (0 < m <= 10^5),表示第一棵树和第二棵树的节点个数
- 接下来 n 行,表示第一棵树:第 i (0 < i <= n) 行有 3 个整数,w[i] (0 < w[i] <= 10), lc[i], rc[i] (0 < lc[i], rc[i] <= n),分别表示节点 i 的权值,该节点的左孩子编号和右孩子编号,若某个孩子不存在,则为 0 (数据保证每棵树都是合法的有根二叉树)
- 接下来 m 行,表示第二棵树:格式同第一棵树
保证:树的最大深度不会超过 10000。
Output
对于每组数据,输出一行一个整数 num,表示第一棵树的所有子树中与第二棵树完全相同的个数。
Example Input
7 4 1 6 3 2 0 4 1 7 0 3 0 0 1 2 1 2 0 0 2 0 0 2 0 0 1 4 0 1 1 2 2 0 0 3 3 1 0 0 2 1 3 3 0 0 1 0 3 2 1 0 3 0 0
Example Output
1 0
Hint
数据量比较大,推荐用 scanf 等读入。
题意:
有两颗二叉树分别有n个和m个顶点,求前一棵树中有多少子树与后一棵树完全相同(不考虑节点编号)
输入n m
输入n行a b c表示该号节点权值为a,左右儿子分别是b和c(0表示不存在该儿子)
输入m行
代码:
//想不到可以kmp,将两棵树的前序遍历写出来(节点权值),不存在的节点要补0,然后将得到的两个串 //进行kmp找后一个串在前一个串中出现了多少次。 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int MAXN=400009; struct Node{ int l,r,w; }node[2][MAXN]; int N,M,cnt,len1,len2; int ch[2][MAXN]; bool vis[MAXN]; int f[MAXN],f2[MAXN]; void dfs(int id,int rt){ ch[id][cnt++]=node[id][rt].w; if(node[id][rt].l!=0){ dfs(id,node[id][rt].l); }else{ ch[id][cnt++]=0; } if(node[id][rt].r!=0){ dfs(id,node[id][rt].r); }else{ ch[id][cnt++]=0; } } void getfail(int* P,int* f){ f[0]=0;f[1]=0; f2[0]=0;f2[1]=0; for(int i=1;i<len2;i++){ int j=f2[i]; while(j&&P[i]!=P[j]) j=f2[j]; f2[i+1]=f[i+1]=(P[i]==P[j]?j+1:0); if(f[i+1]==j+1&&P[i+1]==P[j+1]) f[i+1]=f[j+1]; } } int find(int* T,int* P,int* f){ getfail(P,f); int j=0,ans=0; for(int i=0;i<len1;i++){ while(j&&P[j]!=T[i]) j=f[j]; if(P[j]==T[i]) j++; if(j==len2) ans++; } return ans; } int main() { while(scanf("%d%d",&N,&M)==2){ int a,b,c,rt1,rt2; memset(vis,0,sizeof(vis)); for(int i=1;i<=N;i++){ scanf("%d%d%d",&a,&b,&c); node[0][i].w=a; node[0][i].l=b; node[0][i].r=c; vis[b]=vis[c]=1; } for(int i=1;i<=N;i++)if(!vis[i]){ rt1=i;break; } memset(vis,0,sizeof(vis)); for(int i=1;i<=M;i++){ scanf("%d%d%d",&a,&b,&c); node[1][i].w=a; node[1][i].l=b; node[1][i].r=c; vis[b]=vis[c]=1; } for(int i=1;i<=M;i++)if(!vis[i]){ rt2=i;break; } cnt=0; dfs(0,rt1); len1=cnt; cnt=0; dfs(1,rt2); len2=cnt; int ans=find(ch[0],ch[1],f); printf("%d\n",ans); } return 0; }