【DP】 HDU 3689 Infinite monkey theorem 预处理

点击打开链接

题意:一只猴子可以有n个键 可以敲m下

求能敲出目标串的概率。

思路:可以先求不能敲出目标串的概率

用 dp[i][j] 表示 敲第 i 下时, 得到 目标串  j  结尾 的概率   

 例: 目标串 word    

wcwor   这是dp[ 5 ][ 3 ] 的状态。。


如果目标串是 aaaaabaaaa   这样的 

 就会转移到奇怪的地方。。


所以先预处理出 每个状态转移的下个状态

然后很方便的算出来了。。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PI;
double p[123];
double dp[1200][20];
int to[12][134];
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m),n+m)
    {
        memset(dp,0,sizeof(dp));
        memset(p,0,sizeof(p));
        for(int i=0;i<n;i++)
        {
            char x[3];
            double y;
            scanf("%s%lf",x,&y);
            p[x[0]]=y;
        }
        char s[123],str[123],lenn=1;
        memset(str,0,sizeof(str));
        scanf("%s",s+1);
        int len=strlen(s+1);
        memset(to,-1,sizeof(to));
        for(int i=1;i<=len;i++)//预处理 , str 为状态串
        {
            for(int j='a';j<='z';j++)
            {
                str[lenn]=j;//当前串能转移到哪里
                for(int k=1;k<=lenn+1;k++)//得到 状态串 与 ( lenn长度 ) 的目标串的最大后缀长度
                {
                    int flag=0;
                    for(int w=k,st=1;w<=lenn;w++,st++)
                    {
                        if(s[st]!=str[w])
                            flag=1;
                    }
                    //第i个位置加j字母的位置
                    if(flag==0)
                    {
                        to[i-1][j]=lenn-k+1;//下一个状态
//                        printf("%s %d\n",str+1,to[i][j]);
                        break;
                    }
                }

            }
            str[lenn++]=s[i];
        }
        dp[0][0]=1;
        for(int i=1;i<=m;i++)
        {
            for(int j=0;j<len;j++)
            {
                for(int k='a';k<='z';k++)
                {
                    if(to[j][k]!=-1&&p[k]!=0)
                    {
                        dp[i][to[j][k]]+=dp[i-1][j]*p[k];
//                        cout<<i<<" "<<to[j][k]<<" "<<dp[i-1][j]*p[k]<<endl;
                    }
                }
            }
        }
        double ans=0;
        for(int i=0;i<len;i++)
            ans+=dp[m][i];
        printf("%.2lf%%\n",100.0-ans*100);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值