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 }
代码君

 

转载于:https://www.cnblogs.com/AOQNRMGYXLMV/p/4394173.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值