zoukankan      html  css  js  c++  java
  • Aho_Corasick自动机(AC自动机)

    首先,AC自动机不是Accept自动机,别以为把这段代码复制到OJ上就全都自动AC了……

    其实这玩意是Aho-Corasick 造出来的,所以你懂的。
    那么这玩意能干嘛咧?
    •字符串的匹配问题
    •多串的匹配问题※
    看不懂吧?解释一下:
    例如给几个单词 acbs,asf,dsef,再给出一个 很长的文章,acbsdfgeasf,问在这个文章中,总共出现了多少个单词,或者是单词出现的总次数。
    怎么实现的呢,就是KMP+trie树。是以KMP为算法基础,trie为索引结构的东东。那它如何与kmp联系在一起?
    •关键是在trie树上加了一种fail指针。
    •Fail指针的用途:就像是kmp中的next的数组。
    在字符串失配的时候确定转移的节点。AC难点就是指针的算法,看下面这么多图:
     
    模板:
      1 #include <cstdio>
      2 #include <iostream>
      3 #include <algorithm>
      4 #include <cstring>
      5 #include <cmath>
      6 #include <queue>
      7 #define REP(i, s, n) for(int i = s; i <= n; i ++)
      8 #define RAP(i, n, s) for(int i = n; i >= s; i --)
      9 #define now ch[x][c]
     10 using namespace std;
     11 const int maxn = 400000 + 10;
     12 const int maxsig = 2;
     13 char S[10000 + 10];
     14 int n;
     15 inline void read(int &x){
     16     x = 0; int sig = 1; char ch = getchar();
     17     while(!isdigit(ch)) { if(ch == '-') sig = -1; ch = getchar(); }
     18     while(isdigit(ch)) x = 10 * x + ch - '0', ch = getchar();
     19     x *= sig; return ;
     20 }
     21 inline void write(int x){
     22     if(x == 0) { putchar('0'); return; }
     23     if(x < 0) putchar('-'), x = -x;
     24     int len = 0, buf[20];
     25     while(x) buf[len ++] = x % 10, x /= 10;
     26     RAP(i, len - 1, 0) putchar(buf[i] + '0'); return ;
     27 }
     28 namespace Aho_Corasick{
     29     int ch[maxn][maxsig], val[maxn], f[maxn], last[maxn], len[maxn], ms;
     30     void AC_init(){
     31         ms = 0;
     32         memset(ch, 0, sizeof(ch));
     33         memset(val, 0, sizeof(val));
     34         memset(f, 0, sizeof(f));
     35         memset(last, 0, sizeof(last));
     36         memset(len, 0, sizeof(len));
     37         return ;
     38     }
     39     void insert(char* s, int v){
     40         int x = 0, i;
     41         for(i = 0; s[i] != ''; i ++){
     42             int c = s[i] - '0'; if(!now) now = ++ ms; x = now;
     43         }
     44         val[x] = v; len[x] = i; return ;
     45     }
     46     void getfail(){
     47         queue<int> Q;
     48         REP(i, 0, maxsig - 1) if(ch[0][i]) Q.push(ch[0][i]);
     49         while(!Q.empty()){
     50             int x = Q.front(); Q.pop();
     51             REP(c, 0, maxsig - 1){
     52                 if(!now) { now = ch[f[x]][c]; continue; }
     53                 Q.push(now); int cur = f[x];
     54                 while(cur && !now) cur = f[cur];
     55                 f[now] = ch[cur][c]; last[now] = val[f[now]] ? f[now] : last[f[now]];
     56             }
     57         }
     58         return ;
     59     }
     60     void AC_print(int i, int j){
     61         if(j){
     62             write(val[j]); printf(": ");
     63             write(i - len[j] + 1); printf(" to ");
     64             write(i); putchar('
    ');
     65             AC_print(i, last[j]);
     66         }
     67         return ;
     68     }
     69     void solve(char* T){
     70         int cur = 0;
     71         for(int i = 0; T[i] != ''; i ++){
     72             cur = ch[cur][T[i] - '0'];
     73             if(val[cur]) AC_print(i, cur);
     74             else if(last[cur]) AC_print(i, last[cur]);
     75         }
     76         return ;
     77     }
     78 }using namespace Aho_Corasick;
     79 bool init(){
     80     read(n); if(!n) return false;
     81     AC_init();
     82     REP(i, 1, n) scanf("%s", S), insert(S, i);
     83     return true;
     84 }
     85 void work(int cur){
     86     getfail();
     87     scanf("%s", S);
     88     printf("Case "); write(cur);
     89     printf(":
    ");
     90     solve(S);
     91     return ;
     92 }
     93 void print(){
     94 
     95     return ;
     96 }
     97 int main(){
     98     int Case = 1;
     99     while(init()) work(Case ++);
    100     return 0;
    101 }
  • 相关阅读:
    WPF 登录窗口关闭时打开主窗口
    WPF Expander获得ToggleButton
    .NET Framework 4 与 .NET Framework 4 Client Profile
    WPF 根据枚举值名称 获得枚举值
    WPF KeyDown不响应方向键、Home/End/PgUp/PgDn等功能键
    C# MemoryStream和BinaryFormatter
    VB INET控件的全部用法
    C#写文件方法总结
    C#实现ADSL拨号(源代码例程)
    使用C#实现ADSL自动拨号(原理及封闭类)
  • 原文地址:https://www.cnblogs.com/chxer/p/4390976.html
Copyright © 2011-2022 走看看