基础模板
//基本模板
const int N=2e6+10;
int tree[N][30],tot=0;
bool flag[N];
void add(char *s)
{
int root=0,id,len=strlen(s);
for(int i=0;i<len;i++){
id=s[i]-'a';
if(!tree[root][id]) tree[root][id]=++tot;
root=tree[root][id];
}
flag[root]=true;
}
bool find(char *s)
{
int root=0,id,len=strlen(s);
for(int i=0;i<len;i++){
id=s[i]-'a';
if(!tree[root][id]) return false;
root=tree[root][id];
}
if(flag[root]) return true;
else return false;
}
例题1
/*
hdu 1251
题意:
给出以该字符串为前缀的单词的数量.
*/
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
int tree[N][30],tot=0;
bool flag[N];
int sum[N];
void add(char *s)
{
int root=0,id,len=strlen(s);
for(int i=0;i<len;i++){
id=s[i]-'a';
if(!tree[root][id]) tree[root][id]=++tot;
root=tree[root][id];
sum[root]++;
}
flag[root]=true;
}
int find(char *s)
{
int root=0,id,len=strlen(s);
for(int i=0;i<len;i++){
id=s[i]-'a';
if(!tree[root][id]) return 0;
root=tree[root][id];
}
return sum[root];
}
int main()
{
char s[100];
while(gets(s)){
if(s[0]==NULL) break;
add(s);
}
while(scanf("%s",s)==1){
printf("%d\n",find(s));
}
return 0;
}
例题2
/*
hdu 2072
*/
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int tree[N][30];
int tot=0;
bool flag[N];
int ans=0;
void add(string s)
{
int id,root=0;
for(int i=0;i<s.size();i++){
int id=s[i]-'a';
if(!tree[root][id]) tree[root][id]=++tot;
root=tree[root][id];
}
if(!flag[root]) ans++;
flag[root]=true;
}
void Init()
{
ans=0;
tot=0;
memset(tree,0,sizeof(tree));
memset(flag,false,sizeof(flag));
}
int main()
{
string s,t;
while(getline(cin,s)){
if(s=="#") break;
Init();
stringstream ss(s);
while(ss>>t){
add(t);
}
cout<<ans<<endl;
}
return 0;
}
例题3
/*
poj 2001
题意就是求一个能代表这个字符串的最短前缀,也就是只有这个字符串具有的前缀。
做法很显然,我们先构建好Trie树,然后对每个单词进行find,递
归到直到节点出现次数为1,表示这个节点只有这一个单词走过,返
回就ok。这里我用了string不断拼接字符,然后直接返回,减少了一些代码量。
*/
#include<string>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
using namespace std;
const int N=1e5+10;
int tree[N][30];
int tot=0;
bool flag[N];
int ans=0;
int sum[N];
void add(char *s)
{
//cout<<"s="<<s<<endl;
int id,root=0,len=strlen(s);
for(int i=0;i<len;i++){
int id=s[i]-'a';
if(!tree[root][id]) tree[root][id]=++tot;
root=tree[root][id];
sum[root]++;
}
if(!flag[root]) ans++;
flag[root]=true;
}
string findth(char *s)
{
string ans="";
int id,len=strlen(s),root=0;
for(int i=0;i<len;i++){
id=s[i]-'a';
root=tree[root][id];
ans+=s[i];
if(sum[root]==1) return ans;
}
return ans;
}
char str[1010][30];
int cc;
int main()
{
while(scanf("%s",str[cc++])==1){
add(str[cc-1]);
}
for(int i=0;i<cc;i++){
printf("%s %s\n",str[i],findth(str[i]).c_str());
}
return 0;
}
例题4
/*
poj 3630
本题题意就是给你一个字符串集合,问你否所有的字符串都不是其他人的前缀。
首先我们构造出Trie树,然后对每个字符串find,当find的路径上如果出现其他字符串结尾标记,
就说明其他字符串是当前字符串的前缀。
注意这里对每个字符串find的时候只要搜索到len?1 len-1len?1即可,如果搜索到len lenlen,
那么将会将本身的字符串统计进去。
*/
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
const int maxn =2e6+5;
int tree[maxn][15];
bool flagg[maxn];
int tot;
void insert_(char *str)
{
int len=strlen(str);
int root=0;
for(int i=0;i<len;i++)
{
int id=str[i]-'0';
if(!tree[root][id]) tree[root][id]=++tot;
root=tree[root][id];
}
flagg[root]=true;
}
int find_(char *str)
{
int len=strlen(str);
int root=0;
for(int i=0;i<len-1;i++)
{
int id=str[i]-'0';
root=tree[root][id];
if(flagg[root]) return true;//路径上出现过其他字符串的结尾标记
}
return false;
}
char ss[10005][12];
int main()
{
int n,t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s",ss[i]);
insert_(ss[i]);
}
int flag=0;
for(int i=0;i<n;i++)
{
if(find_(ss[i]))
{
flag=1;
break;
}
}
if(flag==0)
printf("YES\n");
else
printf("NO\n");
for(int i=0;i<=tot;i++)
{
flagg[i]=false;
for(int j=0;j<10;j++)
tree[i][j]=0;
}
tot=0;
}
return 0;
}