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

 

posted @ 2018-04-21 16:34  flyawayl  阅读(413)  评论(0编辑  收藏  举报