您的位置:首页 > 其它

AC自动机模板

2015-03-15 17:36 260 查看
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
#include <algorithm>
#define N 500006

using namespace std;

char st[1000005];
char keyword[55];
int n,m;
int next
[26],cnt
,fail
,pos;

//初始化字典树的节点
int newNode ( )
{
    for ( int i  = 0; i < 26 ; i++ ) next[pos][i] = 0;
    fail[pos] = cnt[pos] = 0;
    return pos++;
}

//构建字典树
void insert ( char *s )
{
    int i,p = 0;//p当前为根节点,i为字符串初始位置
    for ( i = 0 ; s[i] ; i++ )
    {
        //获得这一字母的节点,如果不存在,创建新的
        int k = s[i] -'a' , &x = next[p][k];
        p = x?x : x = newnode();
    }
    cnt[p]++; // 位运算要用
}

//通过宽搜构建失败指针
void makeNext ( )
{
    int i;
    queue<int> q;
    q.push(0); // 将根节点放入队列中
    while ( !q.empty() )
    {
        int u = q.front();
        //统计匹配到当前位置能够匹配到的串的个数
        cnt[u] += cnt[fail[u]];
        q.pop ();
        for ( int i = 0 ; i < 26 ; i++ )
        {
            int v = next[u][i];
            //如果v是0,证明不能匹配,所以通过fail指针找到深度小于当前深度但
            //是深度最大的与v和自身的最近公共祖先相邻的与v具有相同字母的节点
            //需要通过fail指针跳转过去
            if ( v == 0 ) next[u][i] = next[fail[u]][i];
            else q.push (v);
            //否则,要将v推到队列中去,用于宽搜 
            if ( u && v )
                fail[v] = next[fail[u]][i];
        }
    }
}

int query ( char *s )
{
    int ret = 0, idx , d = 0;
    for ( int i = 0; s[i]; i++ )
    {
        idx = s[i] -'a';
        d = next[d][idx];
        //将当前位置作为串的结尾能匹配到的串的个数
        ret += cnt[d];
        //将串的个数清0,避免重复统计
        cnt[d] = 0;
    }
    return ret;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: