题目链接:
http://poj.org/problem?id=3630
http://acm.hdu.edu.cn/showproblem.php?pid=1671
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 30683 | Accepted: 9051 |
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:
- Emergency 911
- Alice 97 625 999
- 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
题目大意:
给出一组电话号码,判断其中一个号码是否另一个号码的前缀。
题目分析:
这题用字典树来解决。如果用动态的话,malloc,new和delete这些肯定会超时。
所以只能用静态数组。判断条件优化一下,可以把时间将到100ms以内,可惜我不会优化。
记得静态数组开大一点,10000个号码每个号码10位,开100000最保险了。
动态申请内存跟静态数组,由于POJ使用new这一类动态申请内存超时,只能用静态数组提前把需要的内存申请好。
静态申请数组的话空间复杂度较高,动态申请则时间复杂度较高,各有优缺。
下面给出两种方法的代码:
代码1:动态申请
在hdu可以过,poj则超时。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <queue>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
int flag;
struct sky
{
int path;
int ch;
int end;
sky *next[10];
sky(char ch=' ')
{
this -> ch =ch;
this -> path =this -> end =0;
for(int i=0; i<10; i++)
this -> next[i] =NULL;
}
};
sky *root;
int add(char *s)
{
sky *t=root;
while(*s)
{
int i=*s-'0';
if(t->next[i]==NULL)
t->next[i] = new sky(*s);
t->next[i]->path++;
t=t->next[i];
s++;
if(t->end>0) //判断路径是否重复
return 1;
}
t->end++;
if(t->path>1) return 1; //跟上面一样
return 0;
}
void Delete(sky *x)
{
for(int i=0; i<10; i++)
if(x->next[i]!=NULL)
Delete(x->next[i]);
delete(x);
}
int main()
{
int t;
char num[13];
scanf("%d",&t);
while(t--)
{
root=new sky; //动态申请内存
int n;
scanf("%d",&n);
flag=0;
while(n--)
{
scanf(" %s",num);
flag=add(num);
if(flag) break; //如果已经出现前缀则直接跳出,不处理下面的号码
}
if(n>0)
{
while(n--)
scanf(" %s",num);
}
if(flag) printf("NO\n");
else printf("YES\n");
Delete(root); //不释放内存则会超限
}
return 0;
}
代码2: 静态申请
静态申请可以过poj注意初始化数组和数组大小
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <queue>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
const int N=100000+999;
int flag,cot;
struct sky //这个代码跟上面那个除了申请内存方式不一样别的都一样
{
int path;
int ch;
int end;
sky *next[10];
sky(char ch=' ')
{
this -> ch =ch;
this -> path =this -> end =0;
for(int i=0; i<10; i++)
this -> next[i] = NULL; //在POJ好像不能用nullptr总是编译错误
}
};
sky *root;
sky a[N];//注意数组大小
sky* new_sky() //用来分配已经申请好的内存空间
{
return &a[cot++];
}
int add(char *s)
{
sky *t=root;
while(*s)
{
int i=*s-'0';
if(t->next[i]==NULL)
t->next[i] = new_sky();
t->next[i]->path++;
t=t->next[i];
s++;
if(t->end>0)
return 1;
}
t->end++;
if(t->path>1) return 1;
return 0;
}
int main()
{
int t,n;
char num[13];
scanf("%d",&t);
while(t--)
{
cot=0;//记得初始化 啊
root=new_sky(); //申请内存空间
scanf("%d",&n);
flag=0;
while(n--)
{
scanf(" %s",num);
flag=add(num);
if(flag) break;
}
if(n>0)
{
while(n--)
scanf(" %s",num);
}
if(flag) printf("NO\n");
else printf("YES\n");
memset(a,0,sizeof(a)); //清空内存空间。
}
return 0;
}