前缀(字典树)

  描述:给定N个字符串,求这些字符串的最长公共前缀长度与字符串的个数的乘积的最大值。

   范围:1<=N<=1000000    每个字符串长度小于20000

   样例:

  7

  Jora de Sus
  Orhei
  Jora de Mijloc
  Joreni
  Jora de Jos
  Japca
  Orhejul Vechi

  

  方法一:裸的字典树

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 struct letter{
 5     char d;//节点存的字符 
 6     int son,bro;//左孩子和右兄弟,都是节点编号 
 7     int cnt;//此节点的孩子个数 
 8 };
 9 
10 char line[30000];
11 int N,best=0,gs=0;
12 letter tr[10000001];
13 
14 void insert(char s[]){
15     int len=strlen(s);//字符串长度,也是字符串在树中的深度 
16     int now=0;//当前节点 
17     
18     for(int i=0;i<len;i++){//i表示深度,深度为0的是root,并不是某字符  
19         tr[now].cnt++;
20         
21         if(tr[now].cnt*i>best)//每一个节点都尝试更新答案 
22             best=tr[now].cnt*i;
23         
24         if(tr[now].son==0){//这个节点没有左孩子 
25             tr[++gs].d=s[i];//插入点 
26             tr[now].son=gs;//让gs为now的左孩子 
27             now=gs;//更行当前节点 
28         }
29         else{
30             now=tr[now].son;
31             while(tr[now].d!=s[i]&&tr[now].bro>0){//找到合适的节点插入 
32                 now=tr[now].bro;
33             }
34             if(tr[now].d!=s[i]){
35                 tr[++gs].d=s[i];
36                 tr[now].bro=gs;
37                 now=gs; 
38             } 
39             
40         }
41     }
42     tr[now].cnt++;
43     
44     if(tr[now].cnt*len>best){//这个更新容易漏掉 
45         best=tr[now].cnt*len;
46     }
47     
48     
49 }
50 
51 int main(){
52     scanf("%d",&N);
53     for(int i=1;i<=N;i++){
54         gets(line);
55         insert(line);
56     }
57     cout<<best;
58     return 0;
59 }

 

posted @ 2015-08-08 21:28  CXCXCXC  阅读(530)  评论(0编辑  收藏  举报