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\n",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\n",++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\n",ans);
        }
       return 0;
}
View Code

 

posted @ 2014-09-11 15:34  来自大山深处的菜鸟  阅读(216)  评论(0编辑  收藏  举报