题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1305
http://acm.hdu.edu.cn/showproblem.php?pid=1671
这两题几乎都是一样,所以就一起贴上来了...........
题意:
每个测试实例先输入一个数N(1<=N<=10000),接着输入N个数字串。这些数字串作为电话号码,判断在拨号过程中是否出现干扰的号码,若有干扰的号码则不能打通输出NO,否则输出YES。干扰是这样理解的:一个串T,一个串S,不妨设length(T)<length(S),如果T是S的子串那么就产生干扰,因为假如我要拨S号码,那么我在拨完S号码前一定已经把T号码给拨完了,那么电话就转到T上了。
用字典树先保存所有数据,那么据题意判断是否产生干扰就看每个节点的num值与它的所有存在的子节点的num值之和是否相等,如果不相等那么必然有干扰了。
如果字符串Xn=X1X2....Xn是字符串Ym=Y1Y2....Ym的前缀,有在插入的时候有两种情况:Xn在Yn之前插入,Xn在Yn之后插入。
(1)如果Xn在Yn之前插入,那么在插入Yn的时候必然经过Xn的路径,此时可以根据判断在这条路径上是否已经有结点被标记已经构成完成的字符串序列来判断是否存在Yn的前缀;
(2)如果Xn在Yn之后插入,那么插入完成之后当前指针指向的结点的next数组中的元素必定不全为NULL。
HDU 1671 AC code:
#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;
}
1305 AC code:
#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 num(1);
char str[1001];
while(~scanf("%s",str))
{
root=newset();
is_phone=true;
insert(str);
while(scanf("%s",str),*str!='9')
{
insert(str);
}
if(is_phone) printf("Set %d is immediately decodable\n",num++);
else printf("Set %d is not immediately decodable\n",num++);
}
return 0;
}