Hungry3

梦想到达塔顶的蜗牛

ac自动机模板 知道的勿喷=.=

#include<cstdio>
#include<cstring>
using namespace std;
const int max_node=101;
const int son_num=26;
const int modn=2009;
class ACAutomaton
{
    private:
    //每个节点的儿子,即当前节点的状态转移
    int trie[max_node][son_num];
    //记录题目给的关键数据
    int val[max_node];
    //fail指针
    int fail[max_node];
    //队列,用于广搜计算fail指针
    int Q[max_node];
    //字母对应的ID
    int id[128];
    //已使用节点个数
    int sz;
    //特定题目需要
    int dp[2][max_node][1<<10];
    public:
    void init()
    {
        int i,j;
        fail[0]=0;
        for(i=0;i<son_num;i++)
        id[i+'a']=i;
    }
    //重新建树需要reset
    void reset()
    {
        sz=1;
        memset(trie[0],0,sizeof(trie[0]));
    }
    //将权值为key的字符串s插入trie中
    void insert(char *s,int key)
    {
        int u,c,i,j;
        u=0;
        for(i=0;s[i];i++)
        {
            c=id[s[i]];
            if(!trie[u][c])
            {
                memset(trie[sz],0,sizeof(trie[sz]));
                val[sz]=0;
                trie[u][c]=sz++;
            }
            u=trie[u][c];
        }
        val[u]=key;
    }
    //建立AC自动机,确定每个节点的权值以及状态转移
    void construct()
    {
        int i,j;
        int *s=Q,*e=Q;
        for(i=0;i<son_num;i++)
        {
            if(trie[0][i])
            {
                fail[trie[0][i]]=0;
                *e ++=trie[0][i];
            }
        }
        while(s!=e)
        {
            int u=*s++;
            for(i=0;i<son_num;i++)
            {
                int &v=trie[u][i];
                if(v)
                {
                    *e ++=v;
                    fail[v]=trie[fail[u]][i];
                    //以下一行代码要根据题目所给val的含义来写
                    val[v]|=val[fail[v]];
                }
                else v=trie[fail[u]][i];
            }
        }
    }
    //解题,特定题目需要
    int work(int n,int m,int k)
    {
        int S,T;
        int i,j,a;
        int st,p,res;
        int cnt;
        memset(dp[0],0,sizeof(dp[0]));
        dp[0][0][0]=1;
        S=0;
        while(n--)
        {
            T=1-S;
            memset(dp[T],0,sizeof(dp[T]));
            for(i=0;i<sz;i++)
            {
                for(j=0;j<m;j++)
                {
                    if(dp[S][j][j])
                    {
                        for(k=0;k<son_num;k++)
                        {
                            p=trie[i][k];
                            st=(j|val[p]);
                            dp[T][p][st]+=dp[S][i][j];
                        }
                    }
                }
            }
            S=T;
        }
        res=0;
        for(j=0;j<m;j++)
        {
            cnt=0;
            a=j;
            for(;a;cnt+=(a&1),a>>=1);
            if(cnt<k)continue;
            for(i=0;i<sz;i++)
            {
                res+=dp[S][i][j];
            }
        }
        return res;
    }
}AC;
int main()
{
    int i,j,n,m,k;
    char s[11];
    AC.init();
    while(scanf("%d%d%d",&n,&m,&k),n||m||k)
    {
        AC.reset();
        for(i=0;i<m;i++)
        {
            scanf("%s",s);
            AC.insert(s,(1<<i));
        }
        AC.construct();
        printf("%d\n",AC.work(n,1<<m,k));
    }
}
View Code

构建ac自动机,比较难的是建立fail指针,其余的就是字典树的内容了=.=,顺带贴hh大神的链接

http://www.notonlysuccess.com/index.php/aho-corasick-automaton/

void getfail()
{
    queue<int> q;
    fail[0]=0;
    for(c=0;c<son_num;c++)
    {
        u=trie[0][c];
        if(u)
        {
            fail[u]=0;
            q.push(u);
        }
    }
    while(!q.empty())
    {
        r=q.front();q.pop();
        for(c=0;c<son_num;c++)
        {
            u=trie[r][c];
            if(!u)
            {//如果第r结点的第c个子结点不存在
                //我们就把这个不存在的边补上
                trie[r][c]=trie[fail[r]][c];
                continue;
            }
            //如果该结点存在,就得入队
            q.push(u);
            v=fail[r];
            //沿失配走,直到走到根,或者某个“存在”的子结点
            while(v&&!trie[v][c])v=fail[v];
            fail[u]=trie[v][c];//这里要注意,v只是一个用来找u(即trie[r][c])的fail的一个中间变量
        }
    }
}
View Code

 

posted on 2013-11-10 20:53  Hungry3  阅读(172)  评论(0)    收藏  举报

导航