题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3992
题意是说26个字母一定概率随机出现添加到当前字符串的尾部, 给出若干模式串求该字符串中出现任一模式串的期望的长度, 根据模式串建立AC自动机, 一个字符串对应的是自动机上的一系列状态转移, 所以题目就变成了那一类求从图上某个点出发到达指定点的期望走过的步数的题目, 只不过这里的图就是trie图,由于有fail指针所以图上有环所以需要用到高斯消元求解。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cmath>
using namespace std;
const double eps = 1e-8;
const int N = 1005;
const int C = 26;
int Map[256];
int c;
double A[205][205];
bool inf[205];
double prob[C];
void init() {
for (int i = 0; i < C; i++) {
Map[i + 'a'] = i;
}
}
void gauss() {
int i, j, k, r;
for (i = 0; i < c; i++) {
r = i;
for (j = i + 1; j < c; j++)
if (fabs(A[j][i]) > fabs(A[r][i])) r = j;
if (fabs(A[r][i]) < eps) continue;
if (r != i) for (j = 0; j <= c; j++) swap(A[r][j], A[i][j]);
for (k = 0; k < c; k++) if (k != i)
for (j = c; j >= i; j--)
A[k][j] -= A[k][i] / A[i][i] * A[i][j];
}
}
struct AC {
struct Node {
bool out;
int id;
Node* ch[C];
Node* fail;
void init() {
out = 0;
memset(ch, 0, sizeof(ch));
fail = 0;
}
};
Node* root, * null, * it;
Node* head[N], * que[N];
Node D[N * 10];
int sz;
Node* get_Node() {
it->init();
head[sz] = it;
it->id = sz++;
it++;
return it - 1;
}
void init() {
it = D;
sz = 0;
null = new Node;
null->init();
root = get_Node();
for (int i = 0; i < C; i++)
null->ch[i] = root;
root->fail = null;
}
void add(char* str) {
Node* cur = root;
for (int i = 0; str[i]; i++) {
if (!cur->ch[Map[str[i]]])
cur->ch[Map[str[i]]] = get_Node();
cur = cur->ch[Map[str[i]]];
}
cur->out = 1;
}
void set_fail() {
int st = 0, ed = 0;
que[ed++] = root;
while (st < ed) {
Node* cur = que[st++];
for (int i = 0; i < C; i++) {
Node* t = cur->fail;
if (!cur->ch[i]) {
while (t != null && !t->ch[i]) t = t->fail;
cur->ch[i] = t->ch[i];
continue;
}
que[ed++] = cur->ch[i];
while (t != null && !t->ch[i]) t = t->fail;
cur->ch[i]->fail = t->ch[i];
cur->ch[i]->out |= t->ch[i]->out;
}
}
}
void gao() {
c = sz;
for (int i = 0; i < sz; i++)
fill(A[i], A[i] + sz + 1, 0);
for (int i = 0; i < sz; i++) {
A[i][i] = 1;
if (head[i]->out) {
A[i][sz] = 0;
continue;
}
A[i][sz] = 1;
for (int j = 0; j < C; j++) {
int t = head[i]->ch[j]->id;
A[i][t] -= prob[j];
}
}
gauss();
memset(inf, 0, sizeof(inf));
for (int i = c - 1; i >= 0; i--) {
if (fabs(A[i][i]) < eps && fabs(A[i][c]) > eps) inf[i] = 1;
for (int j = i + 1; j < c; j++)
if (fabs(A[i][j]) > eps && inf[j]) inf[i] = 1;
}
if (inf[0])
puts("Infinity");
else {
if (fabs(A[0][0]) < eps)
puts("0.000000");
else
printf("%.6f\n", A[0][sz] / A[0][0]);
}
}
}ac;
char str[100];
int main() {
int n;
init();
while (~scanf("%d", &n)) {
for (int i = 0; i < 26; i++) {
scanf("%lf", &prob[i]);
}
ac.init();
for (int i = 0; i < n; i++) {
scanf("%s", str);
ac.add(str);
}
ac.set_fail();
ac.gao();
}
return 0;
}