首页 > 代码库 > UVA 11468 Ac自动机+dp

UVA 11468 Ac自动机+dp

        题目意思:给出k个模式串,然后随机生成一个长度为L字符串,每个字符被选中的概率为pi  。 问构造出来的字符串不包含任何模式串的概率。

分析:显然这是一个模式串的母串的匹配,显然需要先构建一个AC自动机。我们用dp[i][j] 表示当前正在构造第i个字符,fail指针在j节点上能构造成功的概率。那么我们可以顺着fail指针向后面的状态。 注意只能扩展有效状态,也即不包含任何模式串的状态。 也即

dp [i][j]->dp[i+1][ch[j][k] ];  ch[j][k] 表示如果选k字符的话的下一状态。

VIEW CODE

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<stack>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<ctime>
#include<stdlib.h>
using namespace std;
const int mmax=2100;


struct AC_trie
{
    double dp[110][mmax];
    int ch[mmax][63];
    int cnt[mmax],Fail[mmax],match[mmax];
    int num,k,L,n;
    char patter[30];
    double p[70];
    int get_id(char c)
    {
        if('0'<=c && c<='9')
            return c-'0';
        if('A'<=c && c<='Z')
            return c-'A'+10;
        if('a'<=c && c<='z')
            return c-'a'+36;
        return 0;
    }
    void init()
    {
        memset(ch,0,sizeof ch);
        memset(match,0,sizeof match);
        memset(cnt,0,sizeof cnt);
        cnt[0]=0;
        num=0;
        memset(p,0,sizeof p);
        memset(dp,0,sizeof dp);
    }

    void read(int n)
    {
        for(int i=0;i<n;i++)
        {
            scanf("%s",patter);
            Insert(patter);
        }
    }

    int newnode()
    {
        num++;
        memset(ch[num],0,sizeof ch[num]);
        cnt[num]=0;
        return num;
    }

    void Insert(char *s)
    {
        int u=0;
        for(int i=0;s[i];i++)
        {
            if(!ch[u][get_id(s[i])])
                ch[u][get_id(s[i])]=newnode();
            u=ch[u][get_id(s[i])];
        }
        cnt[u]++;
        match[u]=1;
    }

    void get_Fail()
    {
        queue<int>q;
        Fail[0]=0;
        for(int i=0;i<62;i++)
        {
            int u=ch[0][i];
            if(u)
            {
                q.push(u);
                Fail[u]=0;
            }
        }
        while(!q.empty())
        {
            int x=q.front();
            q.pop();
            for(int i=0;i<62;i++)
            {
                int u=ch[x][i];
                if(!u)
                {
                    ch[x][i]=ch[Fail[x]][i];
                    continue;
                }
                q.push(u);
                int v=Fail[x];
                while(v && !ch[v][i]) v=Fail[v];
                Fail[u]=ch[v][i];
                match[u] |=match[Fail[u]];
            }
        }
    }
    void work()
    {
        init();
        scanf("%d",&k);
        read(k);
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            char xx[2];
            double dd;
            scanf("%s %lf",xx,&dd);
            p[get_id(xx[0])]=dd;
        }
        scanf("%d",&L);
        get_Fail();
        dp[0][0]=1.0;
        for(int i=0;i<L;i++)
        {
            for(int j=0;j<=num;j++)
            {
                if(!match[j])
                    for(int k=0;k<62;k++)
                        dp[i+1][ch[j][k] ]+=dp[i][j]*p[k];
            }
        }
        double ans=0.0;
        for(int i=0;i<=num;i++)
             if(!match[i]) ans+=dp[L][i];
        printf("%.6lf\n",ans);
    }
}Ac;
int main()
{
    int t,ca=0;
    //freopen("in.txt","r",stdin);
    cin>>t;
    while(t--)
    {
        printf("Case #%d: ",++ca);
        Ac.work();
    }
    return 0;
}


UVA 11468 Ac自动机+dp