题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1671
Phone List
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Problem 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
2 3 911 97625999 91125426 5 113 12340 123440 12345 98346
Sample Output
NO YES
Recommend
lcy | We have carefully selected several similar problems for you: 1075 1247 1800 1677 1298
题目大意:
t组数据,每组数据给出n个电话号码,只有当这些电话号码之间没有彼此的前缀,才能拨打出去,例如9123,911,9112,其中9112是拨打不出去的,因为有一个号码911是9112的前缀。(T-T,敲了半天发现WA,看了题解才搞明白题意,测试样例坑人啊T-T……)
解题思路
挨个比较数据量大,所以要用字典树。每个号码都存入字典树,边存边找,对于当前电话号码,因为长度随机,所以有可能是前面电话号的前缀(如之前9112,当前911),或者前面有电话是它的前缀(如之前911,当前9112),这时候就要判断。所以将每个电话号码的结尾标记,如果遍历当前字符串未完成的时候出现了前面字符串的结尾,说明之前有电话号是当前号码的前缀,如果遍历完当前电话号码之后,字典树下一层还有任何一个结点不为空,说明曾经有一个电话号码是以当前电话号码为前缀的。每组数据的电话号码只适用于当前组,所以用完了清空树就好,而且不清空会内存超限。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
using namespace std;
char s[11];
char a[11];
int f=0;
struct node
{
int end;
node *next[10];//它下面的10个数
node()
{
memset(next,NULL,sizeof(next));
end = 0;
}
};
node *p,*root;
void insert()
{
int i=0,t;
p=root;
while(a[i]!='\0')
{
t=a[i]-'0';
//当前结点为空就建一个在指向它否则直接指向它
if(p->next[t]==NULL)
p->next[t]=new node();
p=p->next[t];
if(p->end)//如果之前串是当前串的前缀,例如之前存了91,现在输入912,当指针指向每一个数的时候看看之前串是不是当前的前缀
f=1;
i++;
}
p->end=1;//当前串存完了记录一下结尾。
for(int j=0;j<=9;++j)
{
if(p->next[j]) //如果当前串是之前串的前缀
{
f=1; //如之前有912这次输入91,结束后p指向912的1,后面还有一个2,说明91是912的前缀
break;
}
}
}
void freetree(node *x)
{
int i;
if(x==NULL)
return ;
for(i=0;i<10;++i)
if(x->next[i]!=NULL)
freetree(x->next[i]);
free(x);
return ;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
f=0;
int n;
scanf("%d",&n);
root = new node();
while(n--)
{
scanf("%s",a);
if(!f)//当前不可以拨打了以后也不可以,就不用搜了
insert();
}
if(!f) printf("YES\n");
else printf("NO\n");
freetree(root);
}
return 0;
}