码迷,mamicode.com
首页 > 其他好文 > 详细

ac自动机小结

时间:2015-04-23 21:27:28      阅读:142      评论:0      收藏:0      [点我收藏+]

标签:

用ac自动机预处理出所有文本串到文本串的安全距离(即不通过病毒串)

说下为什么不加bfs部分的注释部分,因为他会导致所求的距离不是安全距离,而之所以能保证bfs的正确是因为如果两文本串连接会通过病毒部分的话,那么next一定会先到病毒部分,(因为病毒部分一定是在两个文本串之间会导致next一定优先指向病毒串)比如当前串遍历完了接下来会有01两种选择,如果走零一定会走到病毒串,那就得老老实实走1.

技术分享
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<queue>
using namespace std;
const int maxa = 60000;
const int cha = 2;
int dp[10][1024];
int dis[10][maxa];
int point[10];
int n, m, k;
int leng[10];
struct Tire{
    int next[maxa][cha], fail[maxa], end[maxa];
    int root, L;
    int newnode(){
        for(int i = 0; i < cha; i++){
            next[L][i] = -1;
        }
        end[L++] = 0;
        return L-1;
    }
    void init(){
        L = 0;
        root = newnode();
    }
    int insert(char buf[], int ii){
        int len = strlen(buf);
        int now = root;
        for(int i = 0; i < len; i++){
            int x = buf[i] -0;
            if(next[now][x] == -1)
                next[now][x] = newnode();
            now = next[now][x];
            //printf("%d ", now);
        }//puts("");
        end[now] = ii;
        return now;
    }
    void build(){//printf("build\n");
        queue<int>Q;
        fail[root] = root;
        for(int i = 0; i < cha; i++){
            if(next[root][i] == -1)
                next[root][i] = root;
            else{
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        }
        while(!Q.empty()){
            int now = Q.front();
            Q.pop();
            end[now] |= end[fail[now]];
            for(int i = 0; i < cha; i++){
                if(next[now][i] == -1)
                    next[now][i] = next[fail[now]][i];
                else{
                    fail[next[now][i]] = next[fail[now]][i];
                    Q.push(next[now][i]);
                   // printf("**%d %d\n",next[now][i],next[fail[now]][i]);
                }
            }
        }
    }
    void bfs(int ii){//printf("bfs\n");
        queue<int> que;
        int vis[maxa];
        memset(vis, 0, sizeof(vis));
        que.push(point[ii]);
        vis[0] = 1;
        dis[ii][point[ii]] = 0;
        while(!que.empty()){
            int now = que.front(); que.pop();//printf("%d %d\n", dis[ii][now], now);
            for(int i =0; i < 2; i++){
                int Next = next[now][i];
                if(vis[Next] == 0 && end[Next] != -1){
                    dis[ii][Next] = dis[ii][now] +1;
                    vis[Next] = 1;
                    que.push(Next);
                }
                /*Next = fail[Next];
                while(Next){
                    if(vis[Next] == 0 && end[Next] != -1){
                        dis[ii][Next] = dis[ii][now] +1;
                        vis[Next] = 1;
                        que.push(Next);
                    }
                    Next = fail[Next];
                }*/
            }
        }
    }
    int solve(){
        memset(dis, -1, sizeof(dis));
        for(int i = 0;i < n; i++){
            bfs(i);
        }//printf("solve%d %d\n", dis[0][point[1]], dis[1][point[0]]);//printf("%d %d\n", point[0], point[1]);
        for(int i =0 ;i  < n; i++){
            for(int k = 0; k < (1<<n); k++){
                dp[i][k] = 10000000;
            }
        }
        for(int i = 0; i < n; i++){
            dp[i][(1<<i)] = leng[i];
        }
        for(int i =1 ;i < n; i++){
            for(int k = 0; k < n; k++){
                for(int j = 0; j < (1<<n); j++){
                    if(dp[k][j] < 10000000){
                        for(int h = 0; h < n; h++){
                            if(!(j&(1<<h)) && dp[k][j]!=-1){
                                dp[h][j|(1<<h)] = min(dp[h][j|(1<<h)], dp[k][j] + dis[k][point[h]]);
                            }
                        }
                    }
                }
            }
        }
        int ans = 10000000;
        for(int i = 0; i < n; i++){
            ans = min(ans, dp[i][(1<<n)-1]);
        }
        return ans;
    }
};
char buf[1000005];
Tire ac;
int main(){
    int m;
    while(scanf("%d%d", &n, &m), n+m){
        ac.init();
        for(int i =0 ;i  < n; i++){
            scanf("%s", buf);
            leng[i] = strlen(buf);
            point[i]=ac.insert(buf, 1+i);
        }
        for(int i =0; i < m; i++){
            scanf("%s", buf);
            ac.insert(buf, -1);
        }
        ac.build();
        printf("%d\n", ac.solve());
    }
}
/*
abcdefg
bcdefg
cdef
de
e
ssaabcdefg


*/
View Code

2.poj3341

ac自动机加状压dp加广搜优化

技术分享
#include<iostream>
#include<map>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<queue>
using namespace std;
const int maxa = 500;
const int cha = 4;
int n, m, k;
int num_[4];
map<char, int> mp;
/*struct point{
    short a[4];
    bool operator <(const point& b)const{
        if(a[0] != b.a[0]) return a[0] < b.a[0];
        else if(a[1] != b.a[1]) return a[1] < b.a[1];
        else if(a[2] != b.a[2]) return a[2] < b.a[2];
        else return a[3] < b.a[3];
    }
};
map<point, int>dp[maxa];
map<point, bool> bo;*/
int dp[500][11*11*11*11];
int num[maxa];
struct Tire{
    int next[maxa][cha], fail[maxa];
    long long end[maxa], po[maxa];
    int root, L;
    int newnode(){
        for(int i = 0; i < cha; i++){
            next[L][i] = -1;
        }
        end[L] = 0;
        num[L++] = 0;
        return L-1;
    }
    void init(){
        L = 0;
        root = newnode();
    }
    void insert(char buf[], int ii){
        int len = strlen(buf);
        int now = root;
        for(int i = 0; i < len; i++){
            int x = mp[buf[i]];
            if(next[now][x] == -1)
                next[now][x] = newnode();
            now = next[now][x];
            //printf("%d ", now);
        }//puts("");
        long long one = 1;
        end[now] |= (one<<ii);
    }
    void build(){
        queue<int>Q;
        fail[root] = root;
        for(int i = 0; i < cha; i++){
            if(next[root][i] == -1)
                next[root][i] = root;
            else{
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        }
        while(!Q.empty()){//printf("*");
            int now = Q.front();
            end[now] |= end[fail[now]];
            long long p = end[now];
            while(p){
                num[now] += p%2;
                p /= 2;
            }
            Q.pop();
           // end[now] |= end[fail[now]];
            for(int i = 0; i < cha; i++){
                if(next[now][i] == -1)
                    next[now][i] = next[fail[now]][i];
                else{
                    fail[next[now][i]] = next[fail[now]][i];
                    Q.push(next[now][i]);
                   // printf("**%d %d\n",next[now][i],next[fail[    now]][i]);
                }
            }
        }
    }
    int solve(){//printf("**%d\n", next[1][3]);
        memset(dp, -1, sizeof(dp));
        dp[0][0] = 0;
        bool vis[11*11*11*11];
        memset(vis, 0, sizeof(vis));
        queue<int>que;
        que.push(0);
        while(!que.empty()){
            int now = que.front(); que.pop();
            //printf("%d ", now);
            int wei = 1;
            for(int i =0;i < 4; i++){/*if(now==1){printf("&&\n");
                    printf("%d %d\n", wei, num_[i]);
                }*/
                if(now % (wei*(num_[i]+1)) /wei == num_[i]){
                    wei *= num_[i] +1;
                    continue;
                }
                int Next_state = now+wei;
                if(!vis[Next_state]){
                    vis[Next_state] = 1;
                    que.push(Next_state);
                }
                for(int k = 0; k < L; k++){
                    /*if(k == 1 && now == 1){
                        printf("--%d %d\n", next[k][i],Next_state);
                    }*/
                    if(dp[k][now] == -1)continue;
                    dp[next[k][i]][Next_state] = max(dp[next[k][i]][Next_state], dp[k][now]+num[next[k][i]]);
                }
                wei *= (num_[i]+1);
            }
        }
        int ans = 0;
        int maxn = 1;
        for(int i = 0;i < 4; i++){
            maxn *= num_[i]+1;
        }
            for(int k = 0; k < maxn; k++){
        for(int i = 0; i < L; i++){//printf("%d %d %d\n", i, k, dp[i][k]);
                ans = max(ans, dp[i][k]);
            }
        }return ans;
    }
};
char buf[45];
Tire ac;
int main(){
    //freopen("in.cpp","r", stdin);
    mp[A] = 0;
    mp[T] = 1;
    mp[G] = 2;
    mp[C] = 3;
    int n;
    int Case = 1;
    while(scanf("%d", &n), n != 0){
        memset(num_, 0, sizeof(num_));
        ac.init();
        for(int i = 0; i < n; i++){
            scanf("%s", buf);
            ac.insert(buf, i);
        }
        scanf("%s", buf);
        memset(num, 0, sizeof(num));
        for(int i = 0; buf[i]; i++){
            num_[mp[buf[i]]] ++;
        }
        ac.build();
        printf("Case %d: %d\n", Case ++, ac.solve());
    }
}
/*
abcdefg
bcdefg
cdef
de
e
ssaabcdefg


*/
View Code

3.poj2778

题意,给出一些串,问m个字符组成的串不包含这些串的有多少种情况。

自动机加矩阵快速幂。

矩阵相乘就是第i行第j列的数就是前一个矩阵的第i行,与后一矩阵的第j列,要保证前一个矩阵的列数等于后一个矩阵的行数。

构造的时候,只要把那些通向结点或通向的点的fild指向结点的节点去掉,其他正常

技术分享
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
const int maxa = 105;
const int cha = 4;
#define LL long long
int n, m, k;
map<char, int> mp;
const int mod = 100000;
struct Matrix{
    int a[maxa][maxa];
    Matrix(){
        memset(a, 0, sizeof(a));
    }
    Matrix operator *(const Matrix &b)const
    {
        Matrix ret;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                for(int k=0;k<n;k++)
                {
                    int tmp=(long long)a[i][k]*b.a[k][j]%mod;
                    ret.a[i][j]=(ret.a[i][j]+tmp)%mod;
                }
        return ret;
    }/*
    Matrix operator *(const Matrix &b) const{
        Matrix tmp;
        for(int i =0 ;i < n; i++){;
            for(int j = 0; j < n; j++){
                for(int k = 0;k  <n; k++){
                    LL lo = (LL) (tmp.a[i][j]) + (LL)(a[i][k]) *b.a[k][j];
                    lo %= mod;
                    tmp.a[i][j] = lo;
                }
            }
        }
        return tmp;
    }*/
};
struct Tire{
    int next[maxa][cha], fail[maxa], end[maxa];
    int root, L;
    int newnode(){
        for(int i = 0; i < cha; i++){
            next[L][i] = -1;
        }
        end[L++] = 0;
        return L-1;
    }
    void init(){
        L = 0;
        root = newnode();
    }
    void insert(char buf[]){
        int len = strlen(buf);
        int now = root;
        for(int i = 0; i < len; i++){
            int x = mp[buf[i]];
            if(next[now][x] == -1)
                next[now][x] = newnode();
            now = next[now][x];
            //printf("%d ", now);
        }//puts("");
        end[now] ++;
    }
    void build(){
        queue<int>Q;
        fail[root] = root;
        for(int i = 0; i < cha; i++){
            if(next[root][i] == -1)
                next[root][i] = root;
            else{
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        }
        while(!Q.empty()){
            int now = Q.front();
            if(end[fail[now]]){
                end[now] = 1;
            }
            Q.pop();
           // end[now] |= end[fail[now]];
            for(int i = 0; i < cha; i++){
                if(next[now][i] == -1)
                    next[now][i] = next[fail[now]][i];
                else{
                    fail[next[now][i]] = next[fail[now]][i];
                    Q.push(next[now][i]);
                   // printf("**%d %d\n",next[now][i],next[fail[now]][i]);
                }
            }
        }
    }
    Matrix make_Maxtrix(){
        Matrix tmp;
        for(int i = 0; i < L; i++){
            for(int k = 0; k < cha; k++){
                if(!end[next[i][k]]){
                    tmp.a[i][next[i][k]] ++;
                }
            }
        }
        return tmp;
    }
};
Matrix pow(Matrix a,int m)
{
    Matrix ret;// = Matrix(a.n);
    for(int i = 0; i < n; i++)
        ret.a[i][i]=1;
    Matrix tmp=a;
    while(m)
    {
        if(m&1)ret=ret*tmp;
        tmp=tmp*tmp;
        m>>=1;
    }
    return ret;
}
char buf[1000005];
Tire ac;
int main(){

mp[A] = 0;
mp[T] = 1;
mp[G] = 2;
mp[C] = 3;
    int N, M;
    while(scanf("%d%d", &N, &M)!=EOF){
        ac.init();
        while(N--){
            scanf("%s", buf);
            ac.insert(buf);
        }
        ac.build();
        n =  ac.L;
        Matrix a = ac.make_Maxtrix();
        Matrix b = pow(a, M);;
        int ans =0 ;
        for(int i = 0; i < n ;i++){
            ans += b.a[0][i];
            ans %= mod;
        }printf("%d\n", ans);
    }
}
/*
abcdefg
bcdefg
cdef
de
e
ssaabcdefg


*/
View Code

4.ZOJ 3494 BCD Code(AC自动机+数位DP)

题目:给出一些模式串,给出一个范围[A,B],求出区间内有多少个数,写成BCD之后,不包含模式串

数位dp加ac自动机

技术分享
#include<string.h>
#include<queue>
#include<stdio.h>
#include<iostream>
using namespace std;
const long long maxa = 2005;
const long long cha = 2;
const long long mod = 1000000009;
struct Tire{
    long long next[maxa][cha], fail[maxa], end[maxa];
    long long root, L;
    long long newnode(){
        for(long long i = 0; i < cha; i++){
            next[L][i] = -1;
        }
        end[L++] = 0;
        return L-1;
    }
    void init(){
        L = 0;
        root = newnode();
    }
    void insert(char buf[]){
        long long len = strlen(buf);
        long long now = root;
        for(long long i = 0; i < len; i++){
            long long x = buf[i] - 0;
            if(next[now][x] == -1){
                next[now][x] = newnode();
            }
            now = next[now][x];
        }end[now] = 1;
    }
    void build(){
        queue<int> Q;
        fail[root] = root;
        for(long long i = 0;i < cha; i++){
            if(next[root][i] == -1){
                next[root][i] = root;
            }else{
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        }
        while(!Q.empty()){
            long long now = Q.front();Q.pop();
            if(end[fail[now]])end[now] = 1;
            for(long long i = 0; i < cha; i++){
                if(next[now][i] == -1)
                    next[now][i] = next[fail[now]][i];
                else{
                    fail[next[now][i]] = next[fail[now]][i];
                    Q.push(next[now][i]);
                }
            }
        }
    }
}ac;
/*
struct Trie
{
    int next[2010][2],fail[2010];
    bool end[2010];
    int root,L;
    int newnode()
    {
        for(int i = 0;i < 2;i++)
            next[L][i] = -1;
        end[L++] = false;
        return L-1;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void insert(char buf[])
    {
        int len = strlen(buf);
        int now = root;
        for(int i = 0;i < len ;i++)
        {
            if(next[now][buf[i]-‘0‘] == -1)
                next[now][buf[i]-‘0‘] = newnode();
            now = next[now][buf[i]-‘0‘];
        }
        end[now] = true;
    }
    void build()
    {
        queue<int>Q;
        fail[root] = root;
        for(int i = 0;i < 2;i++)
            if(next[root][i] == -1)
                next[root][i] = root;
            else
            {
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        while(!Q.empty())
        {
            int now = Q.front();
            Q.pop();
            if(end[fail[now]])end[now] = true;
            for(int i = 0;i < 2;i++)
                if(next[now][i] == -1)
                    next[now][i] = next[fail[now]][i];
                else
                {
                    fail[next[now][i]] = next[fail[now]][i];
                    Q.push(next[now][i]);
                }
        }
    }
};
Trie ac;
*/
//位数,节点,是否含有,是否有前导零
long long dp[205][maxa][2][2];
long long Next[maxa][10][2];
void NEXT(long long now, long long kk){
    long long ok = 0;
    long long ii = now;
    for(long long i= 3; i >= 0; i--){
        ii = ac.next[ii][((1<<i)&kk)?1:0];
        if(ac.end[ii]) ok = 1;
    }
    Next[now][kk][0] = ii;
    Next[now][kk][1] = ok;
}

long long init(){
    memset(dp, -1, sizeof(dp));
    for(long long i = 0;i < ac.L; i++){
        for(long long k = 0;k < 10; k ++){
            NEXT(i, k);
        }
    }
}
long long num[maxa];
long long dfs(long long pos, bool limit, bool yes, long long node, bool isZero){
    if(pos == 0){
        return yes^1;
    }
    if(!limit && isZero == 0 && dp[pos][node][yes][isZero]!=-1)
        return dp[pos][node][yes][isZero];
    long long nn = limit? num[pos]:9;
    long long res = 0;
    for(long long i = 0; i <= nn; i++){
        if(isZero&& i == 0)
            res += dfs(pos-1, limit&&i==nn, yes, node, isZero);
        else
            res += dfs(pos-1, limit &&(i == nn), Next[node][i][1]|yes, Next[node][i][0], 0);
        res %= mod;
    }
    if(!limit){
        dp[pos][node][yes][isZero] = res;
    }
    return res;
}
long long ans(char *a){
    long long l = strlen(a);
    for(long long i = 0; i < l ; i++){
        num[l-i] = a[i]-0;
    }
    return dfs(l, 1, 0, 0, 1);
}
void a_1(char *a){
    int l = strlen(a);
    for(int i = l-1; i>= 0; i--){
        if(a[i] == 0){
            a[i] = 9;
        }else{
            a[i] --;break;
        }
    }
}
char buf[maxa], buf1[maxa];
int main(){
    long long t;
    cin>>t;
    while(t--){
        ac.init();
        long long n;
        cin>>n;
        while(n--){
            scanf("%s", buf);
            ac.insert(buf);
        }//printf("*");
        ac.build();
        init();
        scanf("%s%s", buf, buf1);
        a_1(buf);
        cout<<(mod+ans(buf1)- ans(buf))%mod<<endl;
        //printf("%d\n", (mod+ans(buf1)- ans(buf))%mod);
    }
}
/*
999992719
4
1
0
1 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0
1 10000000000000000000000000000
3
00
0101011
0100000
1 10000000000000000000000000000
5
01010101
010001000010
010100000000100
01010011111111111
0101010100001111111
1 10000000000000000000000000000000000000000000000000000000000000000000000000000000000
805306365
426375876
*/
View Code

 

ac自动机小结

标签:

原文地址:http://www.cnblogs.com/icodefive/p/4451679.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!