Trie (前缀树)uva 11732

  但前缀树的字符子集比较大的时候,就不适合我之前建立的前缀树了,我们使用左儿子 右兄弟的方式存储Trie。

  模板如下:

 struct Trie{
   int head[maxnode];
   int next[maxnode];
   int tot[maxnode];
   int ch[maxnode];
   int sz;
   void clears(){head[0]=next[0]=tot[0]=ch[0]=0;sz=1;ans=0;}
   void inserts(char *s){
     int u=0,v,n=strlen(s);
     tot[0]++;
     for (int i=0;i<=n;i++){
       bool yes=false;
       for (v=head[u];v!=0;v=next[v]){
         if (ch[v]==s[i]) {
           yes=true;
           break;
         }
       }
       if (yes==false) {
         v=sz;
         head[sz]=0;
         tot[sz]=0;
         next[sz]=head[u];
         ch[sz]=s[i];
         head[u]=sz;
         sz++;
       }
       u=v;
       tot[u]++;
     }
   }
};

仅供参考;

提供一题例题:uva 11732 

计算每个节点通过单词的个数,然后求每个的子节点两两相乘的和n,n乘以此节点到根节点的深度的二倍。将所有节点都这样计算一遍相加和就是答案。(要单独考虑叶子节点的情况)

我的代码:

#include <cstdio>
#include <cstring>
const int maxnode =4000*1000+10;
using namespace std;
struct Trie{
   int head[maxnode];
   int next[maxnode];
   int tot[maxnode];
   int ch[maxnode];
   int sz;
   long long ans;
   void clears(){head[0]=next[0]=tot[0]=ch[0]=0;sz=1;ans=0;}
   void inserts(char *s){
     int u=0,v,n=strlen(s);
     tot[0]++;
     for (int i=0;i<=n;i++){
       bool yes=false;
       for (v=head[u];v!=0;v=next[v]){
         if (ch[v]==s[i]) {
           yes=true;
           break;
         }
       }
       if (yes==false) {
         v=sz;
         head[sz]=0;
         tot[sz]=0;
         next[sz]=head[u];
         ch[sz]=s[i];
         head[u]=sz;
         sz++;
       }
       u=v;
       tot[u]++;
     }
   }
   void dfs(int depth, int u) {
    if(head[u] == 0)
      ans += tot[u] * (tot[u] - 1) * depth;
    else {
      int sum = 0;
      for(int v = head[u]; v != 0; v = next[v])
        sum += tot[v] * (tot[u] - tot[v]); // 子树v中选一个串,其他子树中再选一个
      ans += sum / 2 * (2 * depth + 1); // 除以2是每种选法统计了两次
      for(int v = head[u]; v != 0; v = next[v])
        dfs(depth+1, v);
    }
  }
};
struct Trie tree;
int main (){
  int n,kase=0;
  while (scanf("%d",&n)!=EOF&&n){
    char s[1010];
    tree.clears();
    for (int i=0;i<n;i++){
      scanf("%s",s);
      tree.inserts(s);
    }
    tree.dfs(0,0);
    printf("Case %d: %lld\n", ++kase, tree.ans);
  }
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值