您的位置:首页 > 产品设计 > UI/UE

POJ 2778 DNA Sequence(AC自动机确定DFA转移图+矩阵快速幂)

2015-03-07 16:17 423 查看
这道题极好的展示了AC自动机在构造转移图DFA上的应用

DFA转移图就是展示状态的转移过程的图,DFA图构造出来后就可以用DP求出任何DNA长度下,任何状态的个数

本题用自动机求出DFA矩阵,那么有

| dp
[0] dp
[1] ... dp
[m] |=|dp[1][0] dp[1][1] ... dp[1][m] | * DFA^(n-1) (m指状态总数)

DP边界矩阵|dp[1][0] dp[1][1] ... dp[1][m] | 也就是DFA的第一行,所以dp
矩阵就是DFA^n

可见用自动机求某类状态转移方程不仅思路简单,而且可以用矩阵快速幂加速状态转移,复杂度log N

我是通过这篇学会的http://hi.baidu.com/ccsu_010/item/7847a3c17f6fe2bc0d0a7b89 ,感谢

//Accepted	796K	360MS	C++	3171B
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long ll;
const int M = 110;
const int mod = 100000;
struct mat
{
    ll a[M][M];
    mat()
    {
        memset(a,0,sizeof(a));
    }
};
mat DFA;

struct node
{
    node *son[4];
    node *fail;
    bool flag;
    int id;
}trie[M],*que[M],*root;

int Index(char x)
{
    switch(x)
    {
        case 'A' : return 0;
        case 'C' : return 1;
        case 'G' : return 2;
        case 'T' : return 3;
    }
}
struct AC
{
    int head,tail,sz;
    node *createnode()
    {
        trie[sz].flag=0;
        memset(trie[sz].son,0,sizeof(trie[sz].son));
        trie[sz].fail=NULL;
        trie[sz].id=sz;
        return &trie[sz++];
    }

    void ini()
    {
        head=tail=0;
        sz=0;
        root=createnode();
    }
    void Insert(char str[])
    {
        node *cur=root;
        for(int i=0;str[i];i++)
        {
            int val=Index(str[i]);
            if(cur->flag) break; 
            // 如果当前插入的已经是危险片段那么就可以不用继续插入了(针对此题而言)
            //要继续插入也可以不过它的后面全要标记成危险片段if(cur->flag) cur->son[val]->flag=true;

            if(cur->son[val]==NULL)
            {
                cur->son[val]=createnode();
            }
            
            cur=cur->son[val];

        }
        cur->flag=true;
    }
    void acfun()
    {
        que[head++]=root;
        while(tail<head)
        {
            node *cur=que[tail++];
            for(int i=0;i<4;i++)
            {
                if(cur->son[i]!=NULL)
                {
                    if(cur==root) cur->son[i]->fail=root;
                    else cur->son[i]->fail=cur->fail->son[i];
                    if(cur->son[i]->fail->flag) cur->son[i]->flag=true; //易遗漏
                    que[head++]=cur->son[i];
                }
                else
                {
                    if(cur==root) cur->son[i]=root;
                    else cur->son[i]=cur->fail->son[i];
                }
            }
        }
    }

}ac;
mat mul(mat m1,mat m2)
{

    mat ans;
    for(int i=0;i<ac.sz;i++)
    for(int j=0;j<ac.sz;j++)
        if(m1.a[i][j])
        for(int k=0;k<ac.sz;k++)
        {
            ans.a[i][k]=(ans.a[i][k]+m1.a[i][j]*m2.a[j][k])%mod;
        }
    return ans;
}
int quickmul(mat m,int n)
{
    mat ans;
    for(int i=0;i<ac.sz;i++) ans.a[i][i]=1;
    while(n)
    {
        if(n&1) ans=mul(ans,m);
        m=mul(m,m);
        n>>=1;
    }
    ll sum=0;
    for(int i=0;i<ac.sz;i++)
    {
        sum+=ans.a[0][i];
    }
    return sum%mod;
}

void ini(){
    ac.ini();
    memset(DFA.a,0,sizeof(DFA.a));
}
int main()
{
    int m,n;
    while(~scanf("%d%d",&m,&n))
    {
        ini();
        while(m--)
        {
            char tmp[15];
            scanf("%s",tmp);
            ac.Insert(tmp);
        }
        ac.acfun();
        for(int i=0;i<ac.sz;i++)
        {
            if(!trie[i].flag)
            {
                for(int j=0;j<4;j++){
                    if(!trie[i].son[j]->flag)
                        DFA.a[i][trie[i].son[j]->id ]++;
                }
            }
        }
        printf("%d\n",quickmul(DFA,n));
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: