zoukankan      html  css  js  c++  java
  • UVA

      建立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
    ", kase++, solve(0, L));
        }
        return 0;
    }
  • 相关阅读:
    逻辑结算的结果是什么类型?比较运算的值是什么类型?
    算术运算有哪些?逻辑运算有哪些?比较运算有哪些?
    为什么要强制类型转换?什么情况下使用强制类型转换?说说强制类型转换的优点和缺点
    Java中如何强制类型转换
    基本数据类型和引用类型的区别
    Go switch语句
    Go 循环
    Go if_else语句
    Go 包
    Go 函数
  • 原文地址:https://www.cnblogs.com/flyawayl/p/8902106.html
Copyright © 2011-2022 走看看