学习了一下静态字典树,特地来写一发试试模板。
第一眼看到静态字典树和链式前项星好像,感觉差不多的思想(链式数组)
链式前项星edge[]数组中存的是一条条边,对于每条边在next中存的是与
这条边同起点的下一条边所在下标。这些同起点的边就组成了一个链表,
只不过这个链表存在数组中,(该数组叫做链式数组),head[]数组存的就是
表头。对每个顶点i可以通过head[i]知道表头,进而找出所有同起点边。
静态字典树和链式前项星一样,先开一个足够大的数组,只不过链式前项星中
存的是一条条边,而静态字典树中存的是一个个点(通俗理解就是字符)。
Trie结构体中有一个next[]数组,这个数组是字符的索引,next数组存的是下一个
字符在trie[]数组中的位置(是不是和链式前项星很像~逃),存入字典树的
一个string的每个字符就组成了一个链表,链表头是trie[0]。
POJ 3630 题目大意:
给你n个电话号码,如果其中有一个电话号码是另一个电话号码的前缀,则输出NO
否则输出YES。如:
12344
123
输出NO
123
12344
输出NO
1234
7657
输出YES
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<cmath>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<cstring>
#include<queue>
#include<stack>
#include<list>
using namespace std;
typedef long long ll;
const int maxn=100000;
const ll INF=1e9;
const ll mod=1e9+7;
struct Trie{
int next[26];
int num;
bool isStr;
void init(){
num=0;
isStr=false;
memset(next,0,sizeof(next));
}
}trie[maxn];
int cnt;
void init(){
cnt=0;
for(int i=0;i<maxn;i++){
trie[i].init();
}
}
void Insert(char *s){
int pre=0;
for(int i=0;s[i];i++){
int id= s[i]-'0';
if(trie[pre].next[id]==0){
trie[pre].next[id]=++cnt;
pre=cnt;
/*
*
*/
trie[pre].num++;
}
else{
pre=trie[pre].next[id];
/*
*
*/
trie[pre].num++;
}
}
trie[pre].isStr=true;
}
bool Find(char *s){
int pre=0;
bool ok=false;
for(int i=0;s[i];i++){
int id=s[i]-'0';
if(trie[pre].next[id]==0){
return ok;
}
pre=trie[pre].next[id];
if(trie[pre].isStr)ok=true;
}
if(pre)ok=true;
return ok;//trie[pre].num;
}
int main()
{
//freopen("A-large.in","r",stdin);
//freopen("A-large.out","w",stdout);
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
init();
char s[30];
int flag=1;
for(int i=0;i<n;i++){
scanf("%s",s);
if( Find(s) )flag=0;
Insert(s);
}
if(flag)puts("YES");
else puts("NO");
}
return 0;
}