题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2463
题意:给定k个模式串,给定n个字母,每个字母均有一个发生概率,给定长度为l,求用给定n个字母构成的长度为l的不包含任何模式串的文本串概率。
思路:利用k个模式串构成Trie,对于每个模式串结尾字母结点,标记为单词结点,求一遍失配边,不同的是,模式串结尾字母结点的失配边所连接的结点应也被标记。从Trie根结点往下走,利用dp[i][j]
表示根结点为i
,剩余j
步的概率,在Trie上记忆化搜索。
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <math.h>
#include <queue>
#include <vector>
using namespace std;
const int N = 4e2 + 10;
const int SIZE = 70;
struct AC {
int ch[N][SIZE];
int sz;
bool ed[N];
int f[N];
double dp[N][105];
bool vis[N][105];
double p[SIZE];
int newnode() {
memset(ch[sz], 0, sizeof(ch[sz]));
ed[sz] = false;
f[sz] = 0;
return sz++;
}
void init() {
sz = 0;
for (int i = 0; i < SIZE; i++)
p[i] = 0;
memset(vis, false, sizeof(vis));
newnode();
}
int idx(char c) {
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'a' && c <= 'z')
return c - 'a' + 10;
else
return c - 'A' + 36;
}
void insert(char *s) {
int u = 0;
for (int i = 0; s[i]; i++) {
int j = idx(s[i]);
if (!ch[u][j])
ch[u][j] = newnode();
u = ch[u][j];
}
ed[u] = true;
}
void getfail() {
queue<int> q;
for (int i = 0; i < SIZE; i++)
if (ch[0][i])
q.push(ch[0][i]);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = 0; i < SIZE; i++) {
int v = ch[u][i];
if (v) {
int r = f[u];
q.push(v);
while (r && !ch[r][i]) r = f[r];
f[v] = ch[r][i];
// 单词结点失配边连向的结点也为单词结点
ed[v] |= ed[f[v]];
}
else {
ch[u][i] = ch[f[u]][i];
}
}
}
}
double dfs(int u, int j) {
if (j == 0)
return 1.0;
if (vis[u][j])
return dp[u][j];
vis[u][j] = true;
dp[u][j] = 0.0;
for (int i = 0; i < SIZE; i++)
if (!ed[ch[u][i]])
dp[u][j] += (p[i] * dfs(ch[u][i], j - 1));
return dp[u][j];
}
}ac;
int main() {
int t_case;
scanf("%d", &t_case);
for (int i_case = 1; i_case <= t_case; i_case++) {
int k, n, l;
char str[30];
scanf("%d", &k);
ac.init();
for (int i = 0; i < k; i++) {
scanf("%s", str);
ac.insert(str);
}
ac.getfail();
scanf("%d", &n);
for (int i = 0; i < n; i++) {
double pi;
scanf("%s%lf", str, &pi);
ac.p[ac.idx(str[0])] = pi;
}
scanf("%d", &l);
printf("Case #%d: %.6lf\n", i_case, ac.dfs(0, l));
}
return 0;
}