字典树



    #include<stdio.h>  
    #include<string.h>  
    #include<stdlib.h>  
    bool is_phone;/*判断是否能成功拨打号码*/  
    struct node  
    {  
        bool flag;/*在数字串最后标记*/  
        struct node *next[10];  
    };  
    struct node *root;  
    struct node *newset()/*新建结点*/  
    {  
        struct node *p=(struct node *)malloc(sizeof(struct node));  
        for(int i=0;i<10;i++)  
        {  
            p->next[i]=NULL;  
        }  
        p->flag=false;/*初始化为false*/  
        return p;  
    }  
    void insert(char *str)/*建立字典树*/  
    {  
        struct node *p;  
        p=root;  
        int len=strlen(str);  
        for(int i=0;i<len;i++)  
        {  
            if(p->next[str[i]-'0']==NULL)/*如果以前没有建立过该结点*/  
            {  
               if(p->flag==false)  
               {  
                   p->next[str[i]-'0']=newset();/*建立新结点*/  
                   p=p->next[str[i]-'0'];  
                   if(i==len-1)/*只有当指向到数字串末尾时,标记结点为true;*/  
                   {  
                       p->flag=true;  
                   }  
                   else  
                   {  
                       p->flag=false;  
                   }  
               }  
               else/*否则说明当前建立的数字串覆盖了以前的数字串(当前更长),不能拨打号码*/  
               {  
                   is_phone=false;  
                   return ;  
                     
               }  
            }  
            else  
            {  
                if(i==len-1&&p->flag==false)/*如果当前号码是以前出现过的号码的前缀(当前更短)*/  
                {  
                    is_phone=false;  
                    return ;  
                }  
                p=p->next[str[i]-'0'];  
            }  
        }  
        return ;  
    }  
    int del(node *t)/*释放内存*/  
    {  
        if(t==NULL) return 0;  
        for(int i=0;i<10;i++)  
        {  
            if(t->next[i]!=NULL)  
            {  
                del(t->next[i]);  
            }  
        }  
        free(t);  
        return 0;  
    }  
    int main()  
    {  
        int ncase,n;  
        char str[1001];  
        scanf("%d", &ncase);  
        while(ncase--)  
        {  
            root=newset();  
            scanf("%d",&n);  
            is_phone=true;  
            for(int i=0;i<n;i++)  
            {  
                scanf("%s",str);  
                insert(str);  
            }  
            if(is_phone) printf("YES\n");  
            else printf("NO\n");  
            del(root);  
        }  
        return 0;  
    }          


HDU1671

拨电话号码,

2
3
911
97625999
91125426
5
113
12340
123440
12345
98346
输出:

NO

YES

用字典树先保存所有数据,那么据题意判断是否产生干扰就看每个节点的num值与它的所有存在的子节点的num值之和是否相等,如果不相等那么必然有干扰了。

如果字符串Xn=X1X2....Xn是字符串Ym=Y1Y2....Ym的前缀,有在插入的时候有两种情况:XnYn之前插入,XnYn之后插入。

 (1)如果Xn在Yn之前插入,那么在插入Yn的时候必然经过Xn的路径,此时可以根据判断在这条路径上是否已经有结点被标记已经构成完成的字符串序列来判断是否存在Yn的前缀;

(2)如果Xn在Yn之后插入,那么插入完成之后当前指针指向的结点的next数组中的元素必定不全为NULL。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值