UVa 11468 (AC自动机 概率DP) Substring

将K个模板串构成一个AC自动机,那些能匹配到的单词节点都称之为禁止节点。

然后问题就变成了在Tire树上走L步且不经过禁止节点的概率。

根据全概率公式用记忆化搜索求解。

  1 #include <cstdio>

  2 #include <cstring>

  3 #include <queue>

  4 using namespace std;

  5 

  6 const int maxnode = 500;

  7 const int sigma_size = 64;

  8 int idx[256];

  9 

 10 struct AhoCorasickAutomata

 11 {

 12     int ch[maxnode][sigma_size];

 13     int match[maxnode];

 14     int f[maxnode];

 15     int sz;

 16 

 17     void init() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); }

 18 

 19     void insert(char* s)

 20     {

 21         int u = 0, n = strlen(s);

 22         for(int i = 0; i < n; i++)

 23         {

 24             int c = idx[s[i]];

 25             if(!ch[u][c])

 26             {

 27                 memset(ch[sz], 0, sizeof(ch[sz]));

 28                 match[sz] = 0;

 29                 ch[u][c] = sz++;

 30             }

 31             u = ch[u][c];

 32         }

 33         match[u] = 1;

 34     }

 35 

 36     void getFail()

 37     {

 38         queue<int> q;

 39         f[0] = 0;

 40         for(int c = 0; c < sigma_size; c++)

 41         {

 42             int u = ch[0][c];

 43             if(u) { f[u] = 0; q.push(u); }

 44         }

 45         while(!q.empty())

 46         {

 47             int r = q.front(); q.pop();

 48             for(int c = 0; c < sigma_size; c++)

 49             {

 50                 int u = ch[r][c];

 51                 if(!u) { ch[r][c] = ch[f[r]][c]; continue; }

 52                 q.push(u);

 53                 int v = f[r];

 54                 while(v && !ch[v][c]) v = f[v];

 55                 f[u] = ch[v][c];

 56                 match[u] |= match[f[u]];

 57             }

 58         }

 59     }

 60 }ac;

 61 

 62 int n;

 63 const int maxl = 100 + 10;

 64 char s[30][30];

 65 double prob[sigma_size];

 66 

 67 int vis[maxnode][maxl];

 68 double d[maxnode][maxl];

 69 

 70 double getProb(int u, int L)

 71 {

 72     if(L == 0) return 1.0;

 73     if(vis[u][L]) return d[u][L];

 74     vis[u][L] = 1;

 75     double& ans = d[u][L];

 76     ans = 0;

 77     for(int c = 0; c < n; c++)

 78         if(!ac.match[ac.ch[u][c]])

 79             ans += prob[c] * getProb(ac.ch[u][c], L-1);

 80     return ans;

 81 }

 82 

 83 int main()

 84 {

 85     //freopen("in.txt", "r", stdin);

 86 

 87     int T;

 88     scanf("%d", &T);

 89     for(int kase = 1; kase <= T; kase++)

 90     {

 91         int k, L;

 92         scanf("%d", &k);

 93         for(int i = 0; i < k; i++) scanf("%s", s[i]);

 94 

 95         scanf("%d", &n);

 96         for(int i = 0; i < n; i++)

 97         {

 98             char s1[9];

 99             scanf("%s%lf", s1, &prob[i]);

100             idx[s1[0]] = i;

101         }

102 

103         ac.init();

104         for(int i = 0; i < k; i++) ac.insert(s[i]);

105         ac.getFail();

106         scanf("%d", &L);

107         memset(vis, 0, sizeof(vis));

108         printf("Case #%d: %.6f\n", kase, getProb(0, L));

109     }

110 

111     return 0;

112 }
代码君

 

你可能感兴趣的:(substring)