#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的前缀,有在插入的时候有两种情况:Xn在Yn之前插入,Xn在Yn之后插入。
(1)如果Xn在Yn之前插入,那么在插入Yn的时候必然经过Xn的路径,此时可以根据判断在这条路径上是否已经有结点被标记已经构成完成的字符串序列来判断是否存在Yn的前缀;
(2)如果Xn在Yn之后插入,那么插入完成之后当前指针指向的结点的next数组中的元素必定不全为NULL。