tire

基础模板

 

//基本模板 
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;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值