uva 11468-Substring ac自动机 + 记忆化搜索

题目大意:给定k个模式串,然后给定在每一步中字母被选中的概率,求获得长度为L的字符串的且其中不包含任何模式串的概率是多少。

 此题既然给定的是模式串,我们首先想到肯定是要建立自动机,但是建立自动机之后该怎么办呢?

这里就要思考,符合题意的串到底该如何求得呢?

ac自动机说道底就是状态的转换。在构造串时就是没每一步选择一个字符,一旦选择了这个字符,那么现在的串的任何后缀不能是任何模式串。因为如果某个后缀是某个模式串,那么肯定不符合题意啊。所以,此题就是在当前字符串在的ac自动机的那个状态上,选择下一个字母,且满足选择的下一个字母与当前字符串组合之后的字符串的任何后缀不是某个模式串。到此使用的算法也就是搜索,以ac自动的状态为当前节点,遍历下一个可以取的字符。同时加个记忆化。


//
//  main.cpp
//  uva 11468 SubString---AC自动机
//
//  Created by XD on 15/8/31.
//  Copyright (c) 2015年 XD. All rights reserved.
//
//ac自动机 + 加记忆化搜索

#include <iostream>
#include <string>
#include <queue>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include<vector>
#include <string.h>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <cstdio>
using namespace std ;
const int maxn =410 ;
const int sigma_size  = 65 ;
double prob[65  ] ;
struct Ahocrosickautomata
{
    int ch[maxn][sigma_size] ;
    int sz , f[maxn] , match[maxn] ;
    void init()
    {
        sz = 1 ;
        memset(ch[0], 0, sizeof(ch[0])) ;
        match[0]  =0 ;
    }
    int idx(char ch)
    {
        if(ch >='A'&& ch<='Z') return ch-'A' ;
        else if (ch >='a'&&ch <= 'z') return ch - 'a' + 26;
        else return ch - '0'  + 52 ;
    }
    void insert(char *s,int v)
    {
        int u = 0 ;
        int len = (int)strlen(s) ;
        for(int i = 0 ; i < len ; i++)
        {
            int j = idx(s[i] );
            if(!ch[u][j])
            {
                memset(ch[sz], 0, sizeof(ch[sz])) ;
                match[sz] = 0 ;
                ch[u][j] = sz++ ;
                
            }
            u = ch[u][j] ;
        }
        match[u]  = v ;
    }
    void getFail()
    {
        f[0] = 0 ;
        queue<int > q ;
        for(int i = 0 ; i < sigma_size ; 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 i = 0 ; i < sigma_size ;i++)
            {
                int u  =ch[r][i] ;
                if(!u) {ch[r][i] = ch[f[r]][i] ; continue;}
                q.push(u) ;
                int v = f[r] ;
                while(v && !ch[v][i]) v = f[v] ;
                f[u] =ch[v][i] ;
                match[u]  |= match[f[u]] ;
            }
        }
    }
    
    
};
Ahocrosickautomata ac ;
int vis[maxn][110] ;
double d[maxn][110] ;
vector<char> alph ;
double getProb(int u ,int L)
{
    if (!L) {
        return 1.0 ;
    }
    if(vis[u][L]) return d[u][L] ;
    vis[u][L] = 1 ;
    double ans = 0 ; d[u][L] = 0 ;
    int len =(int )alph.size() ;
    for (int i = 0 ; i < len ; i++) {
        int v = ac.ch[u][ac.idx(alph[i])]  ;
        if (!ac.match[v]) {
            ans += prob[ac.idx(alph[i])] * getProb(v, L-1) ;
        }
    }
    d[u][L] = ans ;
    return ans ;
}
int main(int argc, const char * argv[]) {
    int  T ; scanf("%d" ,&T) ;
    char c ;int kase = 0,L ;
    char s[25] ;
    while (T--) {
        alph.clear() ;
        ac.init() ;
        int k,n  ;
        scanf("%d" ,&k) ;
        for (int i = 0 ; i < k ; i++) {
            scanf("%s" ,s) ;
            ac.insert(s, 1) ;
        }
        ac.getFail() ;
        scanf("%d" ,&n) ;
        for (int i = 0 ; i < n  ; i++) {
//            scanf(" %c%lf" ,&c , &prob[ac.idx(c)]) ;
            getchar() ;
            scanf("%c" , &c) ;
            scanf("%lf"  ,&prob[ac.idx(c)]) ;
            alph.push_back(c) ;
        }
        memset(vis, 0, sizeof(vis)) ;
        
        scanf("%d" , &L) ;
        printf("Case #%d: %.6lf\n" , ++kase , getProb(0 , L)) ;
        
    }
        return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值