您的位置:首页 > 其它

hdu3689(kmp+概率dp)

2016-07-11 21:05 302 查看
链接:点击打开链接

题意:给出n个字母出现的频率和一个字符串s,求长度为m的字符串含有s的概率

代码:#include <set>
#include <map>
#include <queue>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
char s[1005];
int len,nex[1005];
double dp[1005][1005];
map<char,double> mp;
map<char,double>::iterator ite;
void getnext(){
int i,j;
i=0,j=-1;
nex[i]=j;
while(i<len){
if(j==-1||s[i+1]==s[j+1])
nex[++i]=++j;
else
j=nex[j];
} //nex数组也从下标1开始
}
int main(){
char c,fir;
int n,m,i,j,tt;
double pp,ans,sec;
while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){
mp.clear();
for(i=1;i<=n;i++){
cin>>c>>pp;
mp[c]=pp;
}
scanf("%s",s+1);
len=strlen(s+1);
getnext();
for(i=0;i<=m;i++) //dp[i][j]表示长度是i,匹配到子串的j的概率
for(j=0;j<=len;j++) //所以只要求出nex数组直接转移即可,但要注意
dp[i][j]=0; //当第i位匹配到子串最后一位,不要继续转移,否则
dp[0][0]=1; //后面的概率可能变成条件概率
for(i=0;i<m;i++){
for(j=0;j<len;j++){ //就一个子串,没必要直接上自动机...
if(dp[i][j]){
for(ite=mp.begin();ite!=mp.end();ite++){
fir=ite->first;
sec=ite->second;
if(fir==s[j+1])
dp[i+1][j+1]+=(dp[i][j]*sec);
else{
tt=j;
while(tt&&s[tt+1]!=fir)
tt=nex[tt];
if(s[tt+1]==fir)
tt++;
dp[i+1][tt]+=(dp[i][j]*sec);
}
}
}
}
}
ans=0;
for(i=1;i<=m;i++)
ans+=dp[i][len];
printf("%.2lf%%\n",ans*100);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: