题意:给出一些字符和各自对应的选择概率,随机选择L次后将得到一个长度为L的随机字符串S.给出K个模版串,计算S不包含任何一个串的概率
思路:d[i][j]表示当前在结点i,还要走j步,不碰到任何禁止结点的概率.,在计算last的语句后面加一个val[u]|=val[f[u]],来计算禁止结点
代码:大白书P216
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
#define ll long long
const ll mod = 20071027;
#define nn 10100
int sz, n;
int ch[nn][66];//建树
int val[nn];//记录尾节点
int f[nn];//表示i失配时转移到的新状态
//int last[nn];//表示节点i沿着失配指针往回走时,遇到的下个单词节点编号
double d[nn][110];
int vis[nn][110];
double prob[110];
int chara[110];
struct Aho
{
void init()
{
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
val[0] = 0;
}
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, len = strlen(s);
for (int i = 0; i < len; i++)
{
int c = idx(s[i]);
if (!ch[u][c])
{
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = 1;
}
void get_f()
{
queue<int>q;
f[0] = 0;
for (int c = 0; c < 66; c++)
{
int u = ch[0][c];
if (u)
{
f[u] = 0;
q.push(u);
//last[u] = 0;
}
}
while (!q.empty())
{
int r = q.front();
q.pop();
for (int c = 0; c < 66; c++)
{
int u = ch[r][c];
if (!u)
{
ch[r][c] = ch[f[r]][c];
continue;
}
q.push(u);
int v = f[r];
while (v && !ch[v][c]) v = f[v];
f[u] = ch[v][c];
val[u] |= val[f[u]];
//last[u] = val[f[u]] ? f[u] : last[f[u]];
}
}
}
double getprob(int u, int dep)
{
if (!dep) return 1.0;
if (vis[u][dep]) return d[u][dep];
vis[u][dep] = 1;
double &ans = d[u][dep];
ans = 0.0;
for (int i = 0; i < n; i++)
if (!val[ch[u][chara[i]]])
ans += prob[i] * getprob(ch[u][chara[i]], dep - 1);
return ans;
}
};
char str[30][30];
int main()
{
Aho ac;
int tt = 1, k, t;
scanf("%d", &t);
while (t--)
{
ac.init();
scanf("%d", &k);
for (int i = 0; i < k; i++)
{
scanf("%s", str[i]);
ac.insert(str[i]);
}
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
char op[5];
scanf("%s%lf", op, &prob[i]);
chara[i] = ac.idx(op[0]);
}
int l;
scanf("%d", &l);
ac.get_f();
memset(vis, 0, sizeof(vis));
printf("Case #%d: %.6lf\n", tt++, ac.getprob(0, l));
}
return 0;
}