Uriel's Corner

Research Associate @ Harvard University / Research Interests: Computer Vision, Biomedical Image Analysis, Machine Learning
posts - 0, comments - 50, trackbacks - 0, articles - 594
题意:有n个键,按每个键有一概率Pi,给定一个字符串S,问按m次敲出这个字符串的概率
            现场赛茫茫多的队伍过了这题,可以我们学校两队都没过。。= =
            在HDOJ上组队做杭州赛的题的时候纠结了半天也没过。。赛后听说思路就是KMP,DP,我状态转移处理有问题。。
            今天又搞了一晚上,请教Ziroy大牛之后发现错误原因在s状态不用处理
思路:dp转移方程很好想,dp[i][j]表示已经按了i次,当前状态是j(S的第j个字母),概率是多少
            具体实现过程见代码及注释
           
//Problem: HDOJ 3689
//Source: 2010 Hangzhou Regional On-Site J Infinite monkey theorem
//Solution: KMP+DP(like DFA)
//Status: Accepted
//Running Time: 15Ms
//Author: Uriel
//2010.10.29

#include
<stdio.h>
#include
<string.h>
double dp[1050][20],dd[20];
char st[30],ch[30];
double p[30];
int nxt[30],s;

void GetNext(char* str){
    nxt[
0]=-1;
    
int i=0,j=-1;
    
while(str[i]){
        
if(j==-1 || str[i]==str[j]){
            i
++; j++; nxt[i]=j;
        }

        
else j=nxt[j];
    }

}


int main(){
    
int n,m;
    
int i,j,k;
    
while(scanf("%d %d",&n,&m),n|m){
        
for(i=0;i<n;i++){
            scanf(
"%s",st);
            ch[i]
=st[0];
            scanf(
"%lf",&p[i]);
        }

        scanf(
"%s",st);
        
for(i=0;i<=m;++i){
            
for(j=0;j<=s;++j)dp[i][j]=0.0;
        }

        s
=strlen(st);
        GetNext(st);
        dp[
0][0]=1.0;
        
for(i=1;i<=m;i++)//共按m次
            for(j=0;j<s;j++)//枚举当前状态,不用考虑j=s,因为这时已经满足要求,不用算下去!!
                for(k=0;k<n;++k)//枚举当前这次按哪个键
                    if(!j)//如果当前状态是还没有按出正确串的前缀
                        if(ch[k]==st[0])dp[i][1]+=dp[i-1][0]*p[k]; //如果这次按的是川的第一个字母,状态从0变为1
                        else //否则0状态的概率累加
                            dp[i][0]+=dp[i-1][0]*p[k];
                    }

                    
else if(ch[k]==st[j])//如果当前按对了该串当前状态的后一个字母
                        dp[i][j+1]+=dp[i-1][j]*p[k]; //状态+1
                    }

                    
else{
                        
int tp=j;
                        
while(tp>-1 && ch[k]!=st[tp])tp=nxt[tp]; //利用KMP的Next函数当前状态计算按下k之后的状态(能匹配的前缀长度)
                        if(tp==-1)dp[i][0]+=dp[i-1][j]*p[k]; //如果当前匹配失败,状态变为0,且累加状态0的概率
                        else //否则状态为tp+1,状态tp+1的概率累加
                            dp[i][tp+1]+=dp[i-1][j]*p[k];
                    }

                }

            }

        }

        
double ans=0.0;
        
for(i=1;i<=m;++i)ans+=dp[i][s];//所有长度能得到状态s的概率之和即为所求
        printf("%.2f%%\n",100*ans);
    }

    
return 0;
}

        这么大水的题搞了这么久。。而且字符串又是我的任务。。杯具。。
        下周三去成都,39h45min,第一次坐这么长时间火车。。
        祈祷DSW Chengdu Regional 好运。。Regional是如此的宝贵。。不知道以后还有没有机会。。

Feedback

# re: 2010 Hangzhou Regional On-Site J Infinite monkey theorem---KMP+DP  回复  更多评论   

2012-04-03 08:25 by zjushuiping
请问你的这种代码折叠是怎样做到了?谢谢!

# re: 2010 Hangzhou Regional On-Site J Infinite monkey theorem---KMP+DP  回复  更多评论   

2012-04-03 21:17 by Uriel
@zjushuiping
这个。。cpp blog插入代码的时候可以选的啊。。

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理