POJ3630 Phone List Trie解法详解

Phone List
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 32591 Accepted: 9459

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

 
  1. NO
YES

Source

Nordic 2007

题目分析:给多组数据,每次都给出号码个数以及号码,分别计算这些串中存不存在:某个串是另一个串的前缀,如果有就输出NO,否则输出YES

算法分析:

  1. 暴力解法:本题暴力的'根'在于暴力求解是否为前缀串,其中要考虑到所有串是不是比它大的任意一个串的子串,是否为子串可以一一枚举是否相等或者用Hash判断。因为电话号码最长就10,所以时间复杂度O(N^2)。
  2. Tire字典树的构树性质刚好符合本题的意思,而且事实证明最基本字典树也能AC这道题(虽然卡着时间过得),每次在插入时刚好沿着这条树枝走,走的过程中判断就好

代码如下:

(注意:因为不知道插入的串的长短,可能单调也可能一个长一个短,所以不能只判这个串是不是前面所有串的前缀子串或者有没有别的串是这个串的前缀子串,要保证同时判断!见下面代码的注释)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int trie[1000100][11],ans,tot=1;
char str[11];
bool end[1000100];
inline void Search_(char a[])
{
	int len=strlen(a),p=1;
	for(int k=0;k<len;k++)
	{
		int ch=a[k]-'0';
		if(end[trie[p][ch]])//如果有别的串是当前串的前缀子串:说明当前串在树的路径上应该有别的串的结束点
			ans=1;
		if(k==len-1&&trie[p][ch])ans=1; //如果当前串是前一个串的前缀子串:说明结束位置的点被别的串走过
		if(!trie[p][ch])trie[p][ch]=++tot;
		p=trie[p][ch];
		
	}
	end[p]=true;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int n;
		ans=0;memset(trie,0,sizeof(trie));memset(end,false,sizeof(end));
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%s",str);
			if(!ans)	Search_(str);
		}
		if(!ans)
			printf("YES\n");
		else 
			printf("NO\n");
	}
	return 0;
}

当然也可以保证插入时一定为前面串长度小于后面,这样就只需要判断在这个串的路径上有没有别的串的结束点就行了。具体方法就是离线掉,先把读的数据存起来再按照长短排序,再插入。但这样做意义不大,每次判断两次都是O(1)的。

这种解法全当练习基本字典树。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值