• Keywords Search HDU2222 AC自动机模板题


    ac自动机说起来很复杂,其实和kmp是一样的思路,都是寻找相同前后缀,减少跳的次数。只要理解了kmp是怎么求next数组的,ac自动机bfs甚至比knp还好写。

    这里大致说一下kmp求next数组的方法吧,假设现在要求第c个字符的next值(假设这个c很大,这样画图出来比较清晰方便理解),因为遍历过程中我们已经知道了第c-1个字符的next为x(假设比c小很多),即next[c-1] = x。那就代表我们知道了a[1]—a[x]这一段和a[c-1-x]—a[c-1]这一段是相等的对吧。

    那么现在有两种情况

    一。a[x+1] 和 a[c]相等,那么显然变成了a[1]—a[x+1] 这一段和a[c-1-x]—a[c]这一段相等,即c位置的相同前后缀长度比c-1多了1,就是next[c-1]+1;

    即原来是:

    1——————————x      == c-1-x ————————————————c-1  ① 由于a[x+1] == a[c],变成了

    1——————————x+1  == c-1-x——————————————————c

    二。如果不相等,那么我们在1——x这一段下功夫,假设next[x] = y,即1——y == x-y——x这两段相等,注意根据①式,x-y——x == c-1-y——c-1,画个图就很清楚了,所以如果a[y+1] == a[c],那么相同前后缀长度就是y+1了。

    即因为

    1——————————x   ==    c-1-x————————————————c-1  

    1——y    ==   x-y———x   ==    c-1-x——c-1-x+y     ==       c-1-y————c-1   由于a[y+1] == a[c],变成了

    1——y+1             ==          c-1-y——————c 

    那如果a[y+1] 与a[c]还是不相等怎么办?其实细心的话应该发现这是一个递归过程了——只要再找next[y],循环上面的过程就可以了,想明白这个过程再去看求next数组的代码就很容易理解了。

    最后还是上这道题代码:

      1 #include <iostream>
      2 #include <string.h>
      3 #include <cstdio>
      4 #include <queue>
      5 #include <set>
      6 #include <stack>
      7 #include <math.h>
      8 #include <string>
      9 #include <algorithm>
     10 
     11 #define SIGMA_SIZE 26
     12 #define pii pair<int,int>
     13 #define lson rt<<1
     14 #define rson rt<<1|1
     15 #define lowbit(x) (x&-x)
     16 #define fode(i, a, b) for(int i=a; i>=b; i--)
     17 #define foe(i, a, b) for(int i=a; i<=b; i++)
     18 #define fod(i, a, b) for(int i=a; i>b; i--)
     19 #define fo(i, a, b) for(int i=a; i<b; i++)
     20 //#pragma warning ( disable : 4996 )
     21 
     22 using namespace std;
     23 typedef long long LL;
     24 inline LL LMax(LL a, LL b) { return a>b ? a : b; }
     25 inline LL LMin(LL a, LL b) { return a>b ? b : a; }
     26 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
     27 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
     28 inline int Max(int a, int b) { return a>b ? a : b; }
     29 inline int Min(int a, int b) { return a>b ? b : a; }
     30 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
     31 inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
     32 const LL INF = 0x3f3f3f3f3f3f3f3f;
     33 const LL lmod = 1e9+7;
     34 const int mod = 10000;
     35 const double eps = 1e-8;
     36 const int inf = 0x3f3f3f3f;
     37 const int maxk = 1e5+5;
     38 const int maxm = 510*510;
     39 const int maxn = 5e5+10;
     40 
     41 struct node {
     42     node *fail, *s[26];
     43     int w;
     44     node() {}
     45     
     46     void init() {
     47         fail = NULL;
     48         fo(i, 0, 26) s[i] = NULL;
     49         w = 0;
     50     }
     51 }*head;
     52 
     53 
     54 int n, ans;
     55 char str[1000010];
     56 queue<node*> q;
     57 
     58 node* getfail(node* p, int x)
     59 {
     60     if (p->s[x] != NULL) return p->s[x];
     61     else {
     62         if (p == head) return head;
     63         else return getfail(p->fail, x);
     64     }
     65 }
     66 
     67 void build()
     68 {
     69     node* root = head;
     70     node* tmp;
     71 
     72     int len = strlen(str);
     73     for ( int j = 0; j < len; j++ ) 
     74     {
     75         int k = str[j]-'a';
     76         if (root->s[k] == NULL) {
     77             tmp = new node; tmp->init();
     78             tmp->fail = head;
     79             root->s[k] = tmp; 
     80         }
     81 
     82         root = root->s[k];
     83         //标记单词结尾
     84         if (j == len-1) root->w++;
     85     }
     86 }
     87 
     88 void build_ac()
     89 {
     90     node* r;
     91     while(!q.empty()) q.pop();
     92     q.push(head);
     93     while(!q.empty())
     94     {
     95         r = q.front(); q.pop();
     96         fo(j, 0, 26)
     97         {
     98             if (r->s[j] != NULL) {
     99                 q.push(r->s[j]);
    100                 if (r == head) r->s[j]->fail = head;
    101                 else r->s[j]->fail = getfail(r->fail, j);
    102             }
    103         }
    104     }
    105     return;
    106 }
    107 
    108 void solve()
    109 {
    110     int len = strlen(str);
    111     node *tmp, *r = head;
    112     fo(j, 0, len)
    113     {
    114         int k = str[j]-'a';
    115         //找到前缀
    116         while( r->s[k]==NULL && r != head ) r = r->fail; 
    117         //自动机向下匹配
    118         //如果可以匹配,则进入下一节点,否则返回头节点
    119         r = (r->s[k]==NULL) ? head : r->s[k];
    120         tmp = r;
    121 
    122         //如果单词a出现,则他的前缀也全部出现过
    123         while(tmp != head) {
    124             ans += tmp->w;
    125             tmp->w = 0;
    126             tmp = tmp->fail;
    127         }   
    128     }
    129     return;
    130 }
    131 
    132 
    133 
    134 void init()
    135 {
    136     cin >> n; ans = 0;
    137     head = new node, head->init();
    138     foe(i, 1, n)
    139         scanf("%s", str), build();
    140 
    141     build_ac();
    142     scanf("%s", str);
    143 }
    144 
    145 int main()
    146 {
    147 
    148     #ifndef ONLINE_JUDGE
    149         freopen("input.txt", "r", stdin);
    150     #endif
    151     
    152     int t; cin >> t;
    153     while(t--)
    154     {
    155         init();
    156         solve();
    157         printf("%d
    ", ans);
    158     }
    159 
    160     return 0;
    161 }
    View Code
  • 相关阅读:
    关于设置日期的代码
    图片拉伸方法以及修改图片渲染模式以及如何把一个控制器包装成一个导航控制器
    统一设置导航栏与状态栏代码
    CALayer加阴影后动画卡的处理办法
    Mac下显示隐藏所有文件
    删除当前目录下的所有.svn
    基础知识
    sql 学习5
    c#多线程学习
    xml序列化
  • 原文地址:https://www.cnblogs.com/chaoswr/p/9783281.html
Copyright © 2020-2023  润新知