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
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/--ZHIYUAN/p/6953796.html