hdu1671(trie树(字典树))

来源:互联网 发布:仿天猫商城源码 编辑:程序博客网 时间:2024/06/05 18:05

Description

Given a list of phone numbers, determine if it is consistent in the sense that no number is the prefix of another. Let’s say the phone catalogue listed these numbers: 
1. Emergency 911 
2. Alice 97 625 999 
3. Bob 91 12 54 26 
In this case, it’s not possible to call Bob, because the central would direct your call to the emergency line as soon as you had dialled the first three digits of Bob’s phone number. So this list would not be consistent. 
 

Input

The first line of input gives a single integer, 1 <= t <= 40, the number of test cases. Each test case starts with n, the number of phone numbers, on a separate line, 1 <= n <= 10000. Then follows n lines with one unique phone number on each line. A phone number is a sequence of at most ten digits.
 

Output

For each test case, output “YES” if the list is consistent, or “NO” otherwise.
 

Sample Input

2391197625999911254265113123401234401234598346
 

Sample Output

NOYES


首先贴上trie树的模板,然后这一题可以根据模板改一下子就ok:

#include <iostream>#include<stdio.h>#include<string.h>using namespace std;const int NODE = 1e5+10,CH = 26;/****INPUT:(Lower case)输入n,m输入n个串s1[i]输入m个串s2[i]OUTPUT:对于每个s2[i] 在s1[i]中查找是否存在存在则输出所在s1[i]中的标号  否则输出0*/struct Trie{    int ch[NODE][CH],sz,val[NODE];    /**    ch[u][c]:   节点u指向的c儿子的边    val[u]:     节点u的值    sz:         trie树的size    */    inline int idx(char c)    {        return c-'a';    }    int node()    {        /**        新建(初始化)节点        **/        memset(ch[sz],0,sizeof(ch[sz]));        ///将所有儿子置为空        val[sz]=0;        return sz++;    }    void init()    {        sz=0;        ///trie树根节点为下标0的节点        node();    }    void insert(char *s,int v)    {        int u=0;        for(;*s;s++)        {            int c=idx(*s);            ///如果节点不存在 新建节点 并把值赋给当前节点的c儿子边            if(!ch[u][c])                ch[u][c]=node();            ///继续移动            u=ch[u][c];        }        ///在末尾节点记录信息        val[u]=v;    }    int find(char *s)    {        int u=0;        for(;*s;s++)        {            int c=idx(*s);            ///如果u节点没有c儿子  结束            if(!ch[u][c])                return 0;            u=ch[u][c];        }        return val[u];    }}soul;char s[10000];int main(){    int n,m;    soul.init();    scanf("%d%d\n",&n,&m);    for(int i=1;i<=n;i++)        scanf("%s",s),soul.insert(s,i);    while(m--)    {        scanf("%s",s);        printf("%d\n",soul.find(s));    }    return 0;}


这题有一点点不一样的就是在原模板基础上增加了一个num数组,用这个数组来干嘛呢?当然是记录数据呀~~~~~~神马数据需要记录??这就需要深入理解trie树的深刻含义了:

假设以串:
he
she
his
hers
构造Trie树 可以得到下图


这就是trie树的构建,构建完成之后会发现其实对应的每个公共节点出来的边的ch[i][j]的i都一样!一样的话这就说明求前缀是有路可寻的!因为我们虽然一个个判断前缀时间可能很慢,但是!现在发现了这个规律,那么我们把每个这种节点使用的次数记录下来,这样就可以表示经过这个节点的有多少线段,相当于一种dp思想,经过一次这个节点的数量就增加一次,最后公共前缀就显而易见的在num数组里了。而这题我们将所有数据先存,后来在一个个使用这些数据,那么如果没有前缀肯定是会走到自己的节点末端的,所以num数组求出来的值至少是1,当然,大于1便说明有更长的单词经过了这个节点,那么自然有前缀啦~~~~~

下面是这题解题代码:

#include <iostream>#include<stdio.h>#include<string.h>using namespace std;const int NODE = 1e6+10,CH = 26;int ch[NODE][CH],sz,val[NODE],num[NODE];char a1[100001][15],a2[15];    /**    ch[u][c]:   节点u指向的c儿子的边    val[u]:     节点u的值    sz:         trie树的size    */int idx(char c){return c-'0';}int node(){        /**        新建(初始化)节点        **/        memset(ch[sz],0,sizeof(ch[sz]));        ///将所有儿子置为空        val[sz]=0;        return sz++;}void init(){        sz=0;        ///trie树根节点为下标0的节点        node();}void insert(char *s,int v){        int u=0;        num[u]++;        for(;*s;s++)        {            int c=idx(*s);            ///如果节点不存在 新建节点 并把值赋给当前节点的c儿子边            if(!ch[u][c])                ch[u][c]=node();            ///继续移动          //  cout<<u<<' '<<char(c+'a')<<' '<<ch[u][c]<<endl;            u=ch[u][c];num[u]++;        }        ///在末尾节点记录信息        val[u]=v;}int find(char *s){    int u=0;    for(;*s;s++)    {        int c=idx(*s);       // cout<<u<<' '<<(char)(c+'a')<<' '<<num[u]<<endl;        ///如果u节点没有c儿子  结束            if(!ch[u][c])            return 0;            u=ch[u][c];       // cout<<(char)*s<<endl;    }    return num[u];}int main(){    int t;scanf("%d",&t);    while(t--)    {     init();    memset(num,0,sizeof(num));    int n;    scanf("%d",&n);    for(int i=0;i<n;i++)    {       scanf("%s",a1[i]);        insert(a1[i],i+1);    }    int flag=1;    for(int i=0;i<n;i++)    {        if(find(a1[i])>1)            {printf("NO\n");flag=0;break;}    }    if(flag==1)printf("YES\n");    }    return 0;}











0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 宝2岁宝脾气大怎么办 宝宝比同龄孩子发育晚怎么办 早教机构业绩不好怎么办 孩子上早教课哭怎么办 两岁宝宝哭闹不止怎么办 7个月宝宝怕生疏怎么办 5个月宝宝怕洗澡怎么办 4个月宝宝认人怎么办 2岁宝宝语言迟缓怎么办 宝宝老是哭闹不睡觉怎么办 7岁儿童说话晚怎么办 一岁多的婴儿说话晚该怎么办 宝宝甲低300多怎么办 两岁半宝宝还不怎么会讲话怎么办 宝宝两岁半了还不讲话怎么办 两岁宝宝怕生人怎么办 四岁宝宝不说话怎么办 1岁宝宝牙齿黄斑怎么办 儿子俩周半了就是不说话怎么办 两岁宝宝牙齿上有黑渍怎么办 两岁宝宝牙齿发黑怎么办 求帮助宝宝刷牙不会漱口怎么办 牙膏不小心吞了怎么办 宝宝误吃了牙膏怎么办 宝宝吃了30g牙膏怎么办 孩子把牙膏吞了怎么办 二岁宝宝有蛀牙怎么办 3岁宝宝有蛀牙了怎么办 三岁宝宝夜惊怎么办 小班孩子跳舞不好好跳怎么办 15个月宝宝拉稀怎么办 孩子学习不认真该怎么办 孩子学习不自觉该怎么办 孩子学习压力大该怎么办 分手发信息不回怎么办 两岁宝宝不会回答问题怎么办 分手了我还想他怎么办 两岁宝宝特别不听话怎么办 2岁宝宝争东西怎么办 两岁宝宝钙吸收不好怎么办 1岁宝宝害羞胆小怎么办