zoukankan      html  css  js  c++  java
  • HDU3689 Infinite monkey theorem 无限猴子(字符串DP+KMP)

    题目描述:

    大概的意思就是根据无限猴子定理,无限只猴子坐在打字机旁瞎敲,总有一个能敲出莎士比亚文集。现在给你一个打字机和一只猴子,打字机的每个按钮(共n个)上的字母及猴子按下这个按钮的概率已知,而且猴子只能按m下按钮,又给定一个串,问猴子打出的乱码中含这个串的概率。

    其中n<=26,m<=1000,多组数据,以n=0,m=0结束。以百分数形式输出,保留小数点后2位。

    样例:

    输入:

    4 10
    w 0.25
    o 0.25
    r 0.25
    d 0.25
    word
    2 10
    a 1.0
    b 0.0
    abc
    2 100
    a 0.312345
    b 0.687655
    abab
    0 0

    输出:

    2.73%
    0.00%
    98.54%

    解题思路:

    对于第一组数据(work)

    很显然算法是:0.25*0.25*0.25*0.25*7*100%=2.73%;

    而对于第三组(abab)就不成立了,为什么呢?

    显然是因为第一组没有重复的字母出现,也就是说,如果你的猴子恰好打下了aba,然后它又不幸地打下了a那么也不算太糟,至少你只需要再打一个bab就可以完成任务了。而对于第一只猴子就没有那么幸运了,如果它打下了wor又不幸地打下了r,那么它必须再打下work才能完成任务。

    也就是说,即使你打下了错误的字母,你也有可能创造了一个前缀。

    所以说我们只需要求出一个错误的字符创造出的前缀是谁,就可以更新这个前缀出现的概率了。

    那么考虑用dp[i][j]表示在猴子打下第i个字母时字符串完成到j的匹配的概率。

    而这个由错误创造的前缀是谁,这是不是KMP。

    然而这和普通的KMP不一样,或者我学了假的KMP,这次kmp的next数组存的是这个模式串第i位的值对应存在的前缀的位置,也就是说,这次是成功指针,而非失配指针。

    dp方程就出来了:dp[这一次敲击][最长匹配的新字符最长前缀]=∑dp[上一次敲击][最长匹配](枚举新字符是谁,再进行前缀操作)

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 int n,m;
     6 int l;
     7 bool JDr_is_Handsome=true;
     8 char cmd[10];
     9 char a[1001];
    10 int op[1001];
    11 int nxt[1001];
    12 double p[1001];
    13 double dp[1001][30];
    14 int main()
    15 {
    16     while(JDr_is_Handsome)
    17     {
    18         scanf("%d%d",&n,&m);
    19         if(!n&&!m)
    20             return 0;
    21         memset(dp,0,sizeof(dp));
    22         memset(p,0,sizeof(p));
    23         for(int i=1;i<=n;i++)
    24         {
    25             scanf("%s",cmd+1);
    26             op[i]=cmd[1];
    27             scanf("%lf",&p[i]);
    28         }
    29         scanf("%s",a+1);
    30         l=strlen(a+1);
    31         nxt[1]=0;
    32         for(int i=2,j=0;i<=l;)
    33         {
    34             while(j&&a[j+1]!=a[i])j=nxt[j];
    35             if(a[j+1]==a[i])j++;
    36             nxt[i]=j;
    37             i++;
    38         }
    39         dp[0][0]=1.00;
    40         for(int i=1;i<=m;i++)
    41         {
    42             for(int j=0;j<l;j++)
    43             {
    44                 for(int k=1;k<=n;k++)
    45                 {
    46                     int pos=j;
    47                     while(pos&&a[pos+1]!=op[k])
    48                         pos=nxt[pos];
    49                     if(a[pos+1]==op[k])pos++;
    50                     dp[i][pos]+=dp[i-1][j]*p[k];
    51                 }
    52             }
    53         }
    54         double ans=0;
    55         for(int i=l;i<=m;i++)
    56             ans+=dp[i][l];
    57         printf("%.2lf%%
    ",ans*100.00);
    58     }
    59     return 0;
    60 }
  • 相关阅读:
    Algorithm Gossip (48) 上三角、下三角、对称矩阵
    .Algorithm Gossip (47) 多维矩阵转一维矩阵
    Algorithm Gossip (46) 稀疏矩阵存储
    Algorithm Gossip (45) 费氏搜寻法
    Algorithm Gossip (44) 插补搜寻法
    Algorithm Gossip (43) 二分搜寻法
    Algorithm Gossip (42) 循序搜寻法(使用卫兵)
    Algorithm Gossip (41) 基数排序法
    Algorithm Gossip (40) 合并排序法
    AlgorithmGossip (39) 快速排序法 ( 三 )
  • 原文地址:https://www.cnblogs.com/blog-Dr-J/p/9484738.html
Copyright © 2011-2022 走看看