hdu 1671 phone list(Trie 树)

简介:

 Phone List

            Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3544    Accepted Submission(s): 1191


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
 题目意思很清楚:就是判断输入的电话号码中是否有号码是其他号码的前缀,很显然要用到字典树。根据分析可知:
  如果字符串Xn=X1X2....Xn是字符串Ym=Y1Y2....Ym的前缀,有在插入的时候有两种情况:Xn在Yn之前插入,Xn在Yn之后插入。
  1)如果Xn在Yn之前插入,那么在插入Yn的时候必然经过Xn的路径,此时可以根据判断在这条路径上是否已经有结点被标记已经构成完成的字符串序列来判断是否存在Yn的前缀;
  2)如果Xn在Yn之后插入,那么插入完成之后当前指针指向的结点的next数组中的元素必定不全为NULL。
实现代码:
复制代码
/*hdu 1671 phone list Trie树的应用 2011.10.15*/

#include <iostream>
#define MAX 10
using namespace std;
bool flag;

typedef struct Trie_Node
{
bool isphone;
struct Trie_Node *next[MAX];
}Trie;

void insert(Trie *root,char *phone)
{
Trie *p=root;
while(*phone!='\0')
{
if(p->next[*phone-48]==NULL)
{
Trie *temp=(Trie *)malloc(sizeof(Trie));
temp->isphone=false;
for(int i=0;i<MAX;i++)
{
temp->next[i]=NULL;
}
p->next[*phone-48]=temp;
}
if(p->isphone==true)
flag=true;
p=p->next[*phone-48];
phone++;
}
p->isphone=true;
for(int i=0;i<MAX;i++)
{
if(p->next[i]!=NULL)
{
flag=true;
break;
}
}
}

void del(Trie *root)
{
for(int i=0;i<MAX;i++)
{
if(root->next[i]!=NULL)
{
del(root->next[i]);
}
}
free(root);
}

int main(int argc, char *argv[])
{
int t;
scanf("%d",&t);
while(t--)
{
int i;
int n;
char phone[11];
Trie *root=(Trie *)malloc(sizeof(Trie));
root->isphone=false;
flag=false;
for(i=0;i<MAX;i++)
{
root->next[i]=NULL;
}
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%s",phone);
if(flag!=true)
{
insert(root,phone);
}
}
if(flag==true)
printf("NO\n");
else
printf("YES\n");
del(root); //必须释放空间,否则会报Memory Limited的错误
}
return 0;
}
复制代码
 
当然这道题目也有另一种思路,就是先对电话号码序列进行排序,然后判断相邻的两个号码是否符合条件即可。这种思路利用了一种性质:
存在若干个字符串序列,对于两个字符串序列X[1....n],Y[1....m],如果X是Y的前缀,则在对所有的字符串序列按字典顺序排序后,
X[1..n]和Y[1....m]在位置上必然是直接相邻或者间接相邻的。间接相邻指存在字符串序列Z[1....t],使得X是Z的前缀(X和Z直接相邻),Z是Y的前缀(Z和Y直接相邻),则X和Y也被认为是相邻的。下面证明这条性质:
假设X[1...n]是Y[1....m]的前缀,但是X和Y不相邻,即至少在X和Y之间存在一字符串序列Z[1....t],其中X不是Z的前缀,Z也不是Y的前缀,且字典顺序为X<Z<Y。
证明:
 X不是Z的前缀,并且Z的字典顺序比X大,那么只存在两种情况:
  1)n>=t,这种情况下,必定存在一个i(0<=i<=t)使得X[i]<Z[i],而由假设可知X是Y的前缀,则必有X[i]=Y[i],此时Y的字典顺序小于Z,与条件不符,不成立。
  2)n<t,这种情况下,有两种可能,一种是对于所有的i(0<=i<=n),X[i]=Z[i],但是如此一来X是Z的前缀,与条件不符,不成立;
     另一种可能是存在i(0<=i<=n),使得X[i]<Z[i],与1)中所述情况一样,与条件不符,不成立。
因此假设不成立,从而性质得证。
因此可以利用此性质解决这道题目,题目只需判断是否存在一个号码是否是另一个号码的前缀即可。所以可以先对所有的号码序列进行字典排序,然后判断直接相邻的两个号码是否符号条件即可。如果所有直接相邻的号码都不存在一个号码是另一个号码的前缀,那么这些号码序列中肯定不存在一个号码是另一个号码的前缀。
实现代码:
复制代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

char phone[10000][11];
int cmp(const void* a,const void* b)
{
return strcmp((char*)a,(char*)b);
}

int main(void)
{
int t;
scanf("%d",&t);
while(t--)
{
int i,n;
bool flag=false;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%s",phone[i]);
}
qsort(phone,n,sizeof(phone[0]),cmp);
for(i=0;i<n-1;i++)
{
if(strncmp(phone[i],phone[i+1],strlen(phone[i]))==0)
{
flag=true;
break;
}
}
if(flag==false)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
复制代码
相关文章
poj 3630 Phone List
1 #include 2 #include 3 #include 4 #define N 100005 5 using namespace std; 6 int Trie[N][10]; 7 int nodeN; 8 int main() 9 { 10 in...
659 0
hdu 1671 Phone List
点击打开链接hdu 1671 题意:给定n个电话号码串,问这n个电话号码串中是否存在某一串是其它串的前缀,如果存在输出NO,否则YES 思路:把这n个电话号码串建立成字典树,在插入的时候我们直接判断当前插入的字符串是不是其它串的前缀或者其...
745 0
|
5月前
|
安全 Java
java线程之List集合并发安全问题及解决方案
java线程之List集合并发安全问题及解决方案
861 1
|
4月前
|
Java API Apache
怎么在在 Java 中对List进行分区
本文介绍了如何将列表拆分为给定大小的子列表。尽管标准Java集合API未直接支持此功能,但Guava和Apache Commons Collections提供了相关API。
|
4月前
|
运维 关系型数据库 Java
PolarDB产品使用问题之使用List或Range分区表时,Java代码是否需要进行改动
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。
|
4月前
|
存储 安全 Java
详解Java中集合的List接口实现的ArrayList方法 | Set接口实现的HashSet方法
详解Java中集合的List接口实现的ArrayList方法 | Set接口实现的HashSet方法

热门文章

最新文章