Uva--11468(AC自动机,概率DP)

2015-05-21 23:03:58

题目:白书的例题,给出一些字符和各自对应的概率,然后构造出长为 L 的随机字符串 S。给出 K 个模板串,计算 S 不含任意一个模板串的概率。

思路:首先根据模式串构造出 AC 自动机,然后就是一个概率 DP 了,用 dp[i][j] 表示当前在 i 号节点,还剩 j 个字符,直到结束不经过任何单词结尾点的概率。

  那么这就可以用记忆化搜索来实现,对于每个点扫描所有可行字符,走到下一个所有不是单词结尾的点,累加其概率即可。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MP(a,b) make_pair(a,b)
#define PB(a) push_back(a)

typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int INF = (1 << 30) - 1;
const int MAXN = 410;
const int RA = 62;

int T,K,N,L,num[100];
char s[30][30];
double pro[130];
double dp[MAXN][110];
bool vis[MAXN][110];

int idx(char c){
    if(c >= 'a' && c <= 'z') return c - 'a';
    if(c >= 'A' && c <= 'Z') return c - 'A' + 26;
    else return c - '0' + 52;
}

struct AC_auto{
    int next[MAXN][70],f[MAXN],cnt[MAXN];
    int root,tot;
    void new_node(int p){
        for(int i = 0; i < RA; ++i) next[p][i] = 0;
        f[p] = cnt[p] = 0;
    }
    void init(){
        root = tot = 0;
        new_node(root);
    }
    void insert(char *str){
        int len = strlen(str);
        int p = root;
        for(int i = 0; i < len; ++i){
            int id = idx(str[i]);
            if(next[p][id] == 0){
                next[p][id] = ++tot;
                new_node(tot);
            }
            p = next[p][id];
        }
        cnt[p]++;
    }
    void getfail(){
        queue<int> Q;
        f[root] = root;
        for(int i = 0; i < RA; ++i){
            int u = next[root][i];
            if(u) Q.push(u);
        }
        while(!Q.empty()){
            int x = Q.front(); Q.pop();
            for(int i = 0; i < RA; ++i){
                int u = next[x][i];
                if(u == 0){
                    next[x][i] = next[f[x]][i];
                    continue;
                }
                Q.push(u);
                int v = f[x];
                while(v && next[v][i] == 0) v = f[v];
                f[u] = next[v][i];
                cnt[u] |= cnt[f[u]];
            }
        }
    }
    double Solve(int p,int l){
        if(l == 0) return 1.0;
        if(vis[p][l]) return dp[p][l];
        vis[p][l] = true;
        double &ans = dp[p][l];
        ans = 0.0;
        for(int i = 0; i < N; ++i)
            if(cnt[next[p][num[i]]] == 0)
                ans += pro[i] * Solve(next[p][num[i]],l - 1);
        return ans;
    }
}ac;


int main(){
    scanf("%d",&T);
    for(int tt = 1; tt <= T; ++tt){
        ac.init();
        memset(vis,false,sizeof(vis));
        scanf("%d",&K);
        for(int i = 1; i <= K; ++i){
            scanf("%s",s[i]);
            ac.insert(s[i]);
        }
        ac.getfail();
        char tmp[10];
        double tp;
        scanf("%d",&N);
        for(int i = 0; i < N; ++i){
            scanf("%s %lf",tmp,&tp);
            num[i] = idx(tmp[0]);
            pro[num[i]] = tp;
        }
        scanf("%d",&L);
        printf("Case #%d: %.6f\n",tt,ac.Solve(ac.root,L));
    }
    return 0;
}

 

posted @ 2015-05-21 23:53  Naturain  阅读(118)  评论(0编辑  收藏  举报