2013-team4/code/ac-automation

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

{{{
AC自动机
要跟据题意修改 idx() 和 print() 这两个函数
idx() 为字符到 int 的映射, print() 为找到模板串后调用的函数
!!注意要在使用 find() 前先使用 get_fail()
!!注意插入相同的模式串的时候会被覆盖
}}}
{{{
创建
AC ac;
插入一个长度为 len 的字符串 str, 附加信息为 value
ac.insert(str, len, value);
调用 find 函数前要调用 get_fail
ac.get_fail();
查找, 文本串 s 长度为 len
ac.find(s, len);
}}}
{{{
typedef int DATA;
const int MAXL = 50007, SIGMA = 26;

struct AC{
    int cnt, ch[MAXL][SIGMA], fail[MAXL], last[MAXL];
    bool end[MAXL];
    DATA val[MAXL];
    AC(){
        clear();
    }
    void clear(){
        cnt = 1; 
        end[0] = false;
        memset(ch[0], 0, sizeof(ch[0]));
    }
    int idx(char c){
        return c - 'A';
    }
    void insert(const char *s, int n, DATA value){
        int now = 0;
        for(int c, i = 0; i < n; i++, now = ch[now][c]){
            c = idx(s[i]);
            if(ch[now][c] == 0){
                memset(ch[cnt], 0, sizeof(ch[cnt]));
                end[cnt] = false;
                ch[now][c] = cnt++;
            }
        }
        end[now] = true; val[now] = value;
    }
    void get_fail(){
        queue<int> q;
        fail[0] = 0;
        for(int c = 0; c < SIGMA; c++){
            int u = ch[0][c];
            if(u != 0){
                fail[u] = last[u] = 0;
                q.push(u);
            }
        }
        while(!q.empty()){
            int x = q.front(); q.pop();
            for(int c = 0; c < SIGMA; c++){
                int &y = ch[x][c];
                if(y == 0) y = ch[fail[x]][c];
                else{
                    fail[y] = ch[fail[x]][c];
                    last[y] = end[fail[y]] ? fail[y] : last[fail[y]];
                    q.push(y);
                }
            }
        }
    }
    void print(int pos, int x){
        cout << "find " << val[x] << " end at " << pos << endl;
        if(last[x] != 0) print(pos, last[x]);
    }
    void find(const char *s, int n){
        int now = 0;
        for(int i = 0; i < n; i++){
            int c = idx(s[i]);
            now = ch[now][c];
            if(end[now]) print(i, now);
            else if(last[now] != 0) print(i, last[now]);
        }
    }
};
}}}
AC自动机
要跟据题意修改 idx() 和 print() 这两个函数
idx() 为字符到 int 的映射, print() 为找到模板串后调用的函数
!!注意要在使用 find() 前先使用 get_fail()
!!注意插入相同的模式串的时候会被覆盖
创建
AC ac;
插入一个长度为 len 的字符串 str, 附加信息为 value
ac.insert(str, len, value);
调用 find 函数前要调用 get_fail
ac.get_fail();
查找, 文本串 s 长度为 len
ac.find(s, len);
typedef int DATA;
const int MAXL = 50007, SIGMA = 26;
struct AC{
    int cnt, ch[MAXL][SIGMA], fail[MAXL], last[MAXL];
    bool end[MAXL];
    DATA val[MAXL];
    AC(){
        clear();
    }
    void clear(){
        cnt = 1; 
        end[0] = false;
        memset(ch[0], 0, sizeof(ch[0]));
    }
    int idx(char c){
        return c - 'A';
    }
    void insert(const char *s, int n, DATA value){
        int now = 0;
        for(int c, i = 0; i < n; i++, now = ch[now][c]){
            c = idx(s[i]);
            if(ch[now][c] == 0){
                memset(ch[cnt], 0, sizeof(ch[cnt]));
                end[cnt] = false;
                ch[now][c] = cnt++;
            }
        }
        end[now] = true; val[now] = value;
    }
    void get_fail(){
        queue<int> q;
        fail[0] = 0;
        for(int c = 0; c < SIGMA; c++){
            int u = ch[0][c];
            if(u != 0){
                fail[u] = last[u] = 0;
                q.push(u);
            }
        }
        while(!q.empty()){
            int x = q.front(); q.pop();
            for(int c = 0; c < SIGMA; c++){
                int &y = ch[x][c];
                if(y == 0) y = ch[fail[x]][c];
                else{
                    fail[y] = ch[fail[x]][c];
                    last[y] = end[fail[y]] ? fail[y] : last[fail[y]];
                    q.push(y);
                }
            }
        }
    }
    void print(int pos, int x){
        cout << "find " << val[x] << " end at " << pos << endl;
        if(last[x] != 0) print(pos, last[x]);
    }
    void find(const char *s, int n){
        int now = 0;
        for(int i = 0; i < n; i++){
            int c = idx(s[i]);
            now = ch[now][c];
            if(end[now]) print(i, now);
            else if(last[now] != 0) print(i, last[now]);
        }
    }
};