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; }