又称单词查找树,trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
(以上内容摘自百度百科)
trie树是一种ennnnnnn树,2333333,本弱的表达能力真的是很弱额。那trie树是用来干什么的那?做题的trie树把字符存到节点里,如上所说,他利用字符串的公共前缀节省查询时间。这也说明了trie树的存储方式是对于不同字符串的相同前缀,他们共用一些相同的节点。比如:abcd和abdd,在存abcd的时候发现0号节点(trie树的根节点,用于把首字母就不同的字符串连接起来)没有a这个儿子,就新建一个a,依次往下建,建出一条链,a->b->c->d,然后在建abdd的时候发现0号节点有a这个儿子了,就不在建了,而是 直接跳到a那里,在往下发现a又有b这个儿子了,还是直接跳过去,然后发现b没有d这个儿子,所以新建一个d,然后d又建一个儿子是d。这就是trie树的建树机制啦。上面的例子建出来的树长下面的样子
而具体实现就是用数字来代表字符,开一个数组或者把所有都封装到一个结构体里来表示trie树就可以了。
来看一道模板题https://www.luogu.org/problemnew/show/P1481
风之子刚走进他的考场,就……
花花:当当当当~~偶是魅力女皇——花花!!^^(华丽出场,礼炮,鲜花)
风之子:我呕……(杀死人的眼神)快说题目!否则……-_-###
花花:……咦好冷我们现在要解决的是魔族的密码问题(自我陶醉:搞不好魔族里面还会有人用密码给我和菜虫写情书咧,哦活活,当然是给我的比较多拉*^_^*)。魔族现在使用一种新型的密码系统。每一个密码都是一个给定的仅包含小写字母的英文单词表,每个单词至少包含1个字母,至多75个字母。如果在一个由一个词或多个词组成的表中,除了最后一个以外,每个单词都被其后的一个单词所包含,即前一个单词是后一个单词的前缀,则称词表为一个词链。例如下面单词组成了一个词链:
i int integer
但下面的单词不组成词链:
integer
intern 现在你要做的就是在一个给定的单词表中取出一些词,组成最长的词链,就是包含单词数最多的词链。将它的单词数统计出来,就得到密码了。
风之子:密码就是最长词链所包括的单词数阿……
花花:活活活,还有,看你长得还不错,给你一个样例吧:
输入格式:
这些文件的格式是,第一行为单词表中的单词数N(1<=N<=2000),下面每一行有一个单词,按字典顺序排列,中间也没有重复的单词咧!!
输出格式:
你要提交的文件中只要在第一行输出密码就行啦^^
很显然,答案就是包含单词最多的单词包含了多少单词,并且除它本身外 ,其他单词都得是它的前缀才算被他包含。一眼想到trie树嘛,每个单词插入trie树,在结束的位置记录一下这个位置的点是一个结束位置,但是因为要求的是包含其他单词最多的单词包含了多少单词,所以不只是要在这里记录一下,从这个位置往下的每一个节点都要加一个单词,
就是这里以1节点结尾的单词,包含在以2,3,4结尾的单词里。这个在建完树后加一个dfs处理一遍就好了。
代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 int tree[2005][2005]; 6 int tot; 7 int n; 8 int ans; 9 int end[2005];//记录以被以节点i结尾的单词包含的单词有多少个,当然如果没有以节点i为结尾的单词也还是要记录的,因为下面的节点需要用,所以最后统计的时候只统计叶子节点(也就是最长的那些单词就好了),但是由于是取max,都统计一遍也不会出错 10 string s; 11 void insert()//插入单词 12 { 13 int len=s.length(); 14 int now=0; 15 for(int i=0;i<len;++i)//从根节点开始 16 { 17 int p=s[i]; 18 if(!tree[now][p])tree[now][p]=++tot;//如果没有这个节点,就新建一个 19 now=tree[now][p];//此时肯定是有这个儿子节点的,所以直接跳过去 20 } 21 end[now]++;//以now为结尾的单词数+1 22 } 23 void dfs(int x) 24 { 25 for(int i=0;i<=2000;++i) 26 if(tree[x][i]) 27 { 28 end[tree[x][i]]+=end[x]; 29 dfs(tree[x][i]); 30 } 31 } 32 int main() 33 { 34 scanf("%d",&n); 35 for(int i=1;i<=n;++i) 36 { 37 cin>>s; 38 insert(); 39 } 40 dfs(0); 41 for(int i=0;i<=2000;++i)ans=max(ans,end[i]); 42 printf("%d",ans); 43 return 0; 44 }