UVA 11468 Substring(AC自动机 + 记忆化搜索)

来源:互联网 发布:淘宝发票抬头哪里设置 编辑:程序博客网 时间:2024/05/23 02:04

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2463

题意:给定k个模式串,给定n个字母,每个字母均有一个发生概率,给定长度为l,求用给定n个字母构成的长度为l的不包含任何模式串的文本串概率。

思路:利用k个模式串构成Trie,对于每个模式串结尾字母结点,标记为单词结点,求一遍失配边,不同的是,模式串结尾字母结点的失配边所连接的结点应也被标记。从Trie根结点往下走,利用dp[i][j]表示根结点为i,剩余j步的概率,在Trie上记忆化搜索。

#include <stdio.h>#include <iostream>#include <string.h>#include <math.h>#include <queue>#include <vector>using namespace std;const int N = 4e2 + 10;const int SIZE = 70;struct AC {    int ch[N][SIZE];    int sz;    bool ed[N];    int f[N];    double dp[N][105];    bool vis[N][105];    double p[SIZE];    int newnode() {        memset(ch[sz], 0, sizeof(ch[sz]));        ed[sz] = false;        f[sz] = 0;        return sz++;    }    void init() {        sz = 0;        for (int i = 0; i < SIZE; i++)            p[i] = 0;        memset(vis, false, sizeof(vis));        newnode();    }    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;        for (int i = 0; s[i]; i++) {            int j = idx(s[i]);            if (!ch[u][j])                ch[u][j] = newnode();            u = ch[u][j];        }        ed[u] = true;    }    void getfail() {        queue<int> q;        for (int i = 0; i < SIZE; i++)            if (ch[0][i])                q.push(ch[0][i]);        while (!q.empty()) {            int u = q.front();            q.pop();            for (int i = 0; i < SIZE; i++) {                int v = ch[u][i];                if (v) {                    int r = f[u];                    q.push(v);                    while (r && !ch[r][i]) r = f[r];                    f[v] = ch[r][i];                    // 单词结点失配边连向的结点也为单词结点                    ed[v] |= ed[f[v]];                }                else {                    ch[u][i] = ch[f[u]][i];                }            }        }    }    double dfs(int u, int j) {        if (j == 0)            return 1.0;        if (vis[u][j])            return dp[u][j];        vis[u][j] = true;        dp[u][j] = 0.0;        for (int i = 0; i < SIZE; i++)            if (!ed[ch[u][i]])                dp[u][j] += (p[i] * dfs(ch[u][i], j - 1));        return dp[u][j];    }}ac;int main() {    int t_case;    scanf("%d", &t_case);    for (int i_case = 1; i_case <= t_case; i_case++) {        int k, n, l;        char str[30];        scanf("%d", &k);        ac.init();        for (int i = 0; i < k; i++) {            scanf("%s", str);            ac.insert(str);        }        ac.getfail();        scanf("%d", &n);        for (int i = 0; i < n; i++) {            double pi;            scanf("%s%lf", str, &pi);            ac.p[ac.idx(str[0])] = pi;        }        scanf("%d", &l);        printf("Case #%d: %.6lf\n", i_case, ac.dfs(0, l));    }    return 0;}
0 0