• ac自动机系列


    hdu2222这题说的是在一个1000000的长串中找出n个短串是否在其中出现过 最后输出在长串中出现的个数

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <map>
    #include <queue>
    #include <string>
    using namespace std;
    const int maxn =10000*50+100;
    const int sign_size = 26;
    map<string,int>ms;
    struct Acuth{
        int ch[maxn][sign_size];
        int val[maxn];
        int sz;
        int f[maxn];
        int last[maxn];
        bool use[10005];
        void clear(){
            memset(ch[0],0,sizeof(ch[0]));
            memset(use,false,sizeof(use));
            sz=1;
            ms.clear();
            val[0]=0;
        }
        int idx(char c){   return c-'a'; }
        void insert(char *s,int v){
            int n = strlen(s), u=0;
            for(int i=0; i<n; ++i){
                int c=idx(s[i]);
                if(ch[u][c]==0){
                   memset(ch[sz],0,sizeof(ch[sz]));
                   val[sz]=0;
                   ch[u][c]=sz++;
                }
                u=ch[u][c];
            }
            ms[string(s)]=v;
            val[u]=v;
        }
        void print(int j){
            if(j){
                 use[val[j]] = true;
                 print(last[j]);
            }
        }
        void find(char *T){
             int n = strlen(T);
             int j=0;
             for(int i=0; i<n; ++i){
                 int c = idx(T[i]);
                 while(j&&!ch[j][c]) j=f[j];
                 j=ch[j][c];
                 if(val[j]) print(j);
                 else if(last[j]) print(last[j]);
             }
        }
        void getFail(){
            queue<int> q;
            f[0]=0;
            for(int c = 0; c<sign_size; ++c){
                  int u = ch[0][c];
                  if(u){  f[u]=0; q.push(u); last[u]=0;   }
            }
           while(!q.empty()){
              int r= q.front(); q.pop();
              for(int c=0; c<sign_size; ++c){
                  int u=ch[r][c];
                  if(!u){ ch[r][c] = ch[f[r]][c]; continue; }
                  q.push(u);
                  int v = f[r];
                  while(v&&!ch[v][c]) v=f[v];
                  f[u]=ch[v][c];
                  last[u] = val[f[u]]?f[u] : last[f[u]];
              }
           }
        }
    }ac;
    char P[10005][55],text[1000005];
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--){
           ac.clear();
           int n;
           scanf("%d",&n);
           for(int i=1; i<=n; ++i){
                scanf("%s",P[i]);
                ac.insert(P[i],i);
           }
           scanf("%s",text);
           ac.getFail();
           ac.find(text);
           int ans=0;
           for(int i=1; i<=n; ++i)
            if(ac.use[ms[string(P[i])]]==true) ans++;
           printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    uva11468 这题给出一些字符和各自对应的选择概率,随机选择L次后将得到一个长度为L 的随机字符串S。给出K个模板串,计算S不包含任何一个串的概率

    利用自动机可以快速匹配多个串的特性进行处理,不断地添加在构造的字符串的末尾位置,如果添加构成一个字符串就不添加否则就添加

    #include <iostream>
    #include <string.h>
    #include <cstdio>
    #include <queue>
    #include <vector>
    using namespace std;
    const int maxn = 20*20+10;
    const int sign_size = 1<<9;
    struct AUthac{
         int ch[maxn][sign_size];
         int val[maxn];
         int sz;
         int f[maxn];
         bool match[maxn];
         void clear(){
              memset(ch[0],0,sizeof(ch[0]));
              sz=1;
              memset(match,false,sizeof(match));
              val[0]=0;
         }
         void insert(char *s,int v){
               int n=strlen(s),u=0;
               for(int i=0; i<n; ++i){
                    int c = s[i];
                    if(ch[u][c]==0){
                       memset(ch[sz],0,sizeof(ch[sz]));
                       val[sz]=0;
                       ch[u][c]=sz++;
                    }
                    u=ch[u][c];
               }
               val[u]=v;
               match[u] = true;
         }
         void getFail(){
              queue<int> q;
              f[0]=0;
              for(int c=0; c<sign_size; c++){
                  int u = ch[0][c];
                  if(u){
                     q.push(u); f[u]=0;
                  }
              }
              while(!q.empty()){
                  int r = q.front(); q.pop();
                  for(int c= 0; c<sign_size; ++c){
                      int u = ch[r][c];
                      if(u==0){
                          ch[r][c]=ch[f[r]][c];continue;
                      }
                      q.push(u);
                      int v = f[r];
                      while( v && !ch[v][c] ) v = f[v] ;
                      f[u]=ch[v][c];
                      match[u] |= match[f[u]];
                  }
              }
         }
    }ac;
    double pro[sign_size];
    char str[sign_size];
    int L,n,K;
    bool vis[maxn][105];
    double dp[maxn][105];
    vector<char> P;
    double dfs(int loc,int leave){
        if(leave==0) return 1;
        if(vis[loc][leave]==true) return dp[loc][leave];
        double ans=0;
        for(int i=0; i<n; ++i){
            int c = P[i];
           if(ac.match[ac.ch[loc][c]]==false)
             ans+= pro[i] * dfs( ac.ch[loc][c], leave - 1 );
        }
        vis[loc][leave] = true;
        dp[loc][leave] = ans;
        return ans;
    }
    int main()
    {
          int t,cas=0;
          char S[30];
          scanf("%d",&t);
          while(t--){
             ac.clear();
             scanf("%d",&K);
             for(int i=1; i<=K; ++i){
                 scanf("%s",S);
                 ac.insert(S,i);
             }
             ac.getFail();
             scanf("%d",&n);
             P.clear();
             for(int i =0; i<n; i++){
                 scanf("%s",str);
                 P.push_back(str[0]);
                 scanf("%lf",&pro[i]);
             }
             memset(vis,false,sizeof(vis));
             scanf("%d",&L);
             double ans=dfs(0,L);
             printf("Case #%d: %.6lf
    ",++cas,ans);
          }
          return 0;
    }
    View Code

    uva11019

    题意 给出一个n*m的字符矩阵T,你的任务是找出给定的x*y的字符矩阵P出现了多少次。 即需要在二维文本串T中查找二维模式串P。

    因为是以矩阵P为模板然后将P的每行都挂在自动机上接下来,如果存在相同的串就讲该串与上一个相同的串用一个next数组存下关系,接下来将文本矩阵T每行都去与自动机匹配每当匹配到一行是 这个行所在的那个矩阵可匹配个数加1(cnt[r][c]表示以r行c列为左上角的矩阵)

    做完所有的行后 统计每个位置为起始点的可匹配数如果等于x那么这就是一个可匹配的矩阵。

    #include <iostream>
    #include <cstdio>
    #include <string.h>
    #include <queue>
    using namespace std;
    const int maxn = 100*100+100;
    const int sign_size = 26;
    int cnt[1001][1001],len[105];
    struct Acuthmechion{
        int ch[maxn][sign_size];
        int val[maxn];
        int sz;
        int next[maxn];
        int f[maxn],last[maxn];
        int idx(char c){ return c-'a';  }
        void clear(){
           sz=1;
           val[0]=0;
           memset(ch[0],0,sizeof(ch[0]));
           memset(cnt,0,sizeof(cnt));
        }
        void insert(char *s,int v){
             int n=strlen(s),u=0;
             len[v]=n;
             for(int i=0; i<n; ++i ){
                int c = idx(s[i]);
                if(ch[u][c]==0){
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz]=0;
                    ch[u][c]=sz++;
                }
                u=ch[u][c];
             }
             next[v]=val[u];
             val[u]=v;
        }
        void print(int row,int colun, int j){
            if(val[j]){
                 for(int i = val[j]; i!=0; i=next[i]){
                     int t1 = row-(i-1);
                     int t2 = colun-(len[i]-1);
                     if(t1>=0&&t2>=0) ++cnt[t1][t2];
                 }
                 print(row,colun,last[j]);
            }
        }
        void find(char *T,int row){
           int n=strlen(T);
           int j=0;
           for(int i=0; i<n; ++i){
              int c = idx(T[i]);
              while(j&&ch[j][c]==0) j=f[j];
              j=ch[j][c];
              if(val[j]) print(row,i,j);
              else if(last[j]) print(row,i,last[j]);
           }
        }
        void geiFail(){
            queue<int> q;
            last[0]=f[0]=0;
            for(int c=0; c<sign_size; ++c){
                int u=ch[0][c];
                if(u){  f[u]=0; q.push(u); last[u]=0;}
            }
            while(!q.empty()){
                int r = q.front(); q.pop();
                for(int c=0; c<sign_size; ++c){
                    int u = ch[r][c];
                    if(u==0){
                         ch[r][c]=ch[f[r]][c]; continue;
                    }
                    q.push(u);
                    int v=f[r];
                    while(v&&ch[v][c]==0) v=f[v];
                    f[u]=ch[v][c];
                    last[u]=val[f[u]] ? f[u]:last[f[u]];
                }
            }
        }
    }ac;
    char xy[105][105];
    char nm[1005][1005];
    int main()
    {
            int cas,n,m,x,y;
            scanf("%d",&cas);
            while(cas--){
                ac.clear();
                 scanf("%d%d",&n,&m);
                 for(int i=0; i<n; ++i)
                   scanf("%s",nm[i]);
                 scanf("%d%d",&x,&y);
                 for(int i=0; i<x; ++i){
                        scanf("%s",xy[i]);
                        ac.insert(xy[i],i+1);
                 }
                 ac.geiFail();
                 for(int i=0; i<n; ++i){
                    ac.find(nm[i],i);
                 }
                 int ans=0;
                 for(int i=0; i<n; ++i)
                    for(int j=0; j<n; ++j)
                     if(cnt[i][j]==x) ans++;
                  printf("%d
    ",ans);
            }
           return 0;
    }
    View Code

  • 相关阅读:
    Python TIPS上一道关于人民币金额小写转大写的题
    C Primer Plus--C预处理器和C库(1)
    C Primer Plus--位操作
    C Primer Plus--结构和其他数据类型(2)
    计算机缓存方式对于程序运行的影响
    7. 整数反转
    服务器初始化安装docker、docker-compose
    nacos爬坑史-1
    Kafka 报错: Error Uncaught exception in scheduled task 'flush-log'
    CentOS中docker部署的项目CPU占用率持续100%以上
  • 原文地址:https://www.cnblogs.com/Opaser/p/3966608.html
Copyright © 2020-2023  润新知