UVA - 11468 (AC自动机+动态规划)
建立AC自动机,把AC自动机当做一张图,在上面跑L个节点就行了。
参考了刘汝佳的代码,发现可能有一个潜在的Bug--如果模式串中出现了没有指定的字符,AC自动机可能会建立出错。
提供一组关于这个BUG的数据:
这组数据我觉得答案应该是1吧,无论如何组合'a'和'b'这两个字符,也无法得到模式串"ac"和"bd"!!
AC代码
#include <stdio.h> #include <string.h> #include <queue> #include <map> using namespace std; const int maxnode = 20 * 20 + 5; const int segma_size = 26 + 26 + 10; const int maxn = 26 + 26 + 10 + 5; const int maxs = 20 + 5; double prob[maxn]; int id[256], n, k; char s[maxs][maxs]; struct Aho{ int ch[maxnode][segma_size]; int f[maxnode]; int match[maxnode]; int sz; void init() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); } void insert(char *s) { int u = 0, n = strlen(s); // try to fix bug for(int i = 0; i < n; i++) { int c = id[s[i]]; if(c == -1) return; } for(int i = 0; i < n; i++) { int c = id[s[i]]; if(!ch[u][c]) { memset(ch[sz], 0, sizeof(ch[sz])); match[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } match[u] = 1; } void getFail() { f[0] = 0; queue<int> q; for(int i = 0; i < n; i++) { int u = ch[0][i]; if(u) { f[u] = 0; q.push(u); } } while(!q.empty()) { int r = q.front(); q.pop(); for(int c = 0; c < n; 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]; match[u] |= match[f[u]]; } } } }ac; double d[maxnode][105]; bool vis[maxnode][105]; double solve(int u, int L) { if(!L) return 1.0; if(vis[u][L]) return d[u][L]; vis[u][L] = true; double &ans = d[u][L]; ans = 0.0; for(int c = 0; c < n; c++) { if(!ac.match[ac.ch[u][c]]) ans += prob[c] * solve(ac.ch[u][c], L-1); } return ans; } int main() { int T, kase = 1; scanf("%d", &T); while(T--) { scanf("%d", &k); for(int i = 0; i < k; i++) { scanf("%s", s[i]); } scanf("%d", &n); char ch[5]; memset(id, -1, sizeof(id)); for(int i = 0; i < n; i++) { scanf("%s%lf", ch, &prob[i]); id[ch[0]] = i; } ac.init(); for(int i = 0; i < k; i++) ac.insert(s[i]); ac.getFail(); int L; scanf("%d", &L); memset(vis, 0, sizeof(vis)); printf("Case #%d: %.6f\n", kase++, solve(0, L)); } return 0; }