用记录附加信息的val数组记录次数即可。
trie的原理:每个可能出现的字目给一个编号c,那么整个树就是一个c叉树
ch[u][c]表示 节点u走c边过去之后的节点
PS:trie树还有种动态写法,使用指针和动态分配内存代替了连续的ch数组,更加节省内存。
Reference:http://blog.csdn.net/architect19/article/details/8966247
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 using namespace std; 5 #define maxnode 400010 6 #define sigma_size 22 7 8 char a[maxnode][sigma_size]; 9 int t[maxnode]; 10 int n,m; 11 //struct Trie 12 //{ 13 int ch[maxnode][sigma_size]; //ch[i][j]:记录结点i的那个编号为j的子节点 14 int val[maxnode]; //val[i]:i节点的附加信息, 15 //若val[i]=0不是还没到单词结束。否则val[i]为该单词的出现次数 16 int sz; 17 void Trie() 18 { 19 sz=1; 20 memset(ch,0,sizeof(ch)); 21 memset(val,0,sizeof(val)); 22 memset(t,0,sizeof(t)); 23 } 24 int idx(char c) //idx(c)即字符c的编号。 25 { 26 //A G C T 27 if (c=='A') return 1; 28 if (c=='G') return 2; 29 if (c=='C') return 3; 30 if (c=='T') return 4; 31 //return c-'A'; //第一个字符是A 32 } 33 void Insert(char s[sigma_size],int v) 34 { 35 int u=0,n=strlen(s); 36 for (int i=0;i<n;i++) 37 { 38 int c=idx(s[i]); 39 if (!ch[u][c]) 40 { 41 memset(ch[sz],0,sizeof(ch[sz])); 42 val[sz]=0; 43 ch[u][c]=sz++; 44 } 45 u=ch[u][c]; 46 } 47 //val[u]=v; 48 val[u]+=v; 49 } 50 int Query(char s[sigma_size]) //times of s 51 { 52 int u=0,c; 53 int tm=strlen(s); 54 for (int i=0;i<tm;i++) 55 { 56 //c=s[i]-'A'; 57 c=idx(s[i]); 58 if (!ch[u][c]) return 0; 59 u=ch[u][c]; 60 //if (val[u]==1) return true; //若此时s还没走完但trie树上已经走到结尾了,即树上单词是s的前缀 61 } 62 return val[u]; 63 } 64 //}; 65 66 int main() 67 { 68 //freopen("in.txt","r",stdin); 69 //ios::sync_with_stdio(false); 70 71 //while (cin>>n>>m) 72 while(~scanf("%d%d",&n,&m)) 73 { 74 Trie(); 75 if ((n!=0)&&(m!=0)) 76 { 77 for (int i=1;i<=n;i++) 78 { 79 //cin>>a[i]; 80 scanf("%s",a[i]); 81 Insert(a[i],1); 82 } 83 for (int i=1;i<=n;i++) 84 { 85 int tm=Query(a[i]); 86 t[tm]++; 87 } 88 for (int i=1;i<=n;i++) 89 printf("%d ",t[i]/i); 90 //cout<<endl; 91 } 92 else break; 93 } 94 95 return 0; 96 }