您的位置:首页 > 其它

杭州现场J题_Infinite monkey theorem

2010-10-26 18:56 351 查看
构造一个DFA, 对于样例:

2 100
a 0.312345
b 0.687655
abab

即:

(b)

-----------

| /

| /

| /

// /

(a) (b) (a) (b)

NULL----->a---->ab---->aba---->abab(ACC,成功状态)

/ / // / / /

| / (a) / / (a) /

| -----------------/----------

| /

| (b) /

--------------------------------

(这幅图画的不错么?= =!)

然后就是DP了, 枚举敲击数i,敲了i个键处于的状态j,按键k,计算出在j这个状态按k会转移到的状态next_t

DP方程:dp[i+1][next_t]+=p[k]*dp[i][j];(dp[i][j]表示敲了i个键后处于j状态的概率)

写的时候脑残的自动机漏了一句话调了n久= =!

然后又用KMP的子串自匹配加状态映射又构造了个DFA,速度竟然比AC自动机慢,不过这题状态这么小怎么都不可能超时的,本来还想写一个暴力构自动机的,实在是没心情遂作罢,顺便还复习了下KMP,还A了道题= =!

PS:计算下标什么的最讨厌了= =!

AC自动机版:

/*
TRIE结构,在使用前必须调用初始化init()!!!
主要调用Ins,ser,返回值都是TRIE中的下标;del,返回有无字符串(删除成功否)
*/
#include<stdio.h>
#include<iostream>
#include<memory.h>
#include<queue>
using namespace std;
const int CTNUM = 26; //储存字母的数目
const int STRNUM = 15000; //节点数目,绝对不能少于给定的字符串数目,一般给大点
const int MINCHAR='a'; //大小写分辨,如果混用或者不连续的话需要有对应的hash函数
struct TRIE
{
int son[CTNUM];
int count;
int father;
}trie[STRNUM];
int fail[STRNUM];
int TNUM=1;
queue<int> q;
int n;
#define INT_MAX 10000000
int map[300][300];
void init()
{
memset(&trie[0],0,sizeof(TRIE));
memset(&trie[1],0,sizeof(TRIE));
TNUM=2;
}
int Ins(char *str,int len)
{
int i;
int cur=1;
for(i=0;i<len;i++)
{
if( !trie[cur].son[str[i]-MINCHAR] )
{
memset( &trie[TNUM],0,sizeof(TRIE) );
trie[TNUM].father=cur;
cur=trie[cur].son[str[i]-MINCHAR]=TNUM++;
}
else cur=trie[cur].son[str[i]-MINCHAR];
}
trie[cur].count++;
return cur;
}
void calc_fail()
{
int i,k,p;
fail[0]=0;
fail[1]=0;
memset(fail,0,sizeof(fail));
while(!q.empty()) q.pop();
q.push(1);
while(!q.empty())
{
i=q.front();
q.pop();
for(k='a'-MINCHAR;k<='z'-MINCHAR;k++)
if (trie[i].son[k]!=0)
{
int p=fail[i];
while(p!=0&&trie[p].son[k]==0)
p=fail[p];
if (!p) fail[trie[i].son[k]]=1;
else
fail[trie[i].son[k]]=trie[p].son[k];
q.push(trie[i].son[k]);
}
}
}
double p[300],dp[1005][50],ans;
char s[300];
int main()
{
int n,m,i,j,x,k,next_t,t;
while(scanf("%d %d",&n,&m)!=EOF)
{
if (n==0&&m==0) break;
memset(p,0,sizeof(p));
for(i=1;i<=n;i++)
{
scanf("%s",s);
scanf("%lf",&p[s[0]-MINCHAR]);
}
scanf("%s",s);
init();
Ins(s,strlen(s));
calc_fail();
ans=0;
memset(dp,0,sizeof(dp));
dp[0][1]=1;
for(i=0;i<=m-1;i++)
for(j=0;j<=TNUM-2;j++)
for(k='a'-MINCHAR;k<='z'-MINCHAR;k++)
{
t=j;
while(t!=0&&trie[t].son[k]==0)
t=fail[t];
if (t==0) next_t=1;
else
next_t=trie[t].son[k];
dp[i+1][next_t]+=p[k]*dp[i][j];
}
for(i=1;i<=m;i++)
ans+=dp[i][TNUM-1];
printf("%.2lf%%/n",ans*100);
}

}

KMP版:

#include<stdio.h>
#include<iostream>
#include<memory.h>
#include<queue>
using namespace std;
const int MINCHAR='a'; //大小写分辨,如果混用或者不连续的话需要有对应的hash函数
int n;
int map[300][300];
int next[100];
void get_next(char *s)
{
int i,j,l;
memset(next,0,sizeof(next));
l=strlen(s);
i=-1;next[0]=-1;j=-1;
for(i=1;i<=l-1;i++)
{
while(s[j+1]!=s[i]&&j!=-1) j=next[j];
if (s[j+1]==s[i]) j++;
next[i]=j;
}
}
double p[300],dp[1005][50],ans;
char s[300];
void calc_map()
{
int i,j,l,t,next_t;
memset(map,0,sizeof(map));
l=strlen(s);
for(i=0;i<=l-1;i++)
for(j='a';j<='z';j++)
{
t=i-1;
while(s[t+1]!=j&&t!=-1) t=next[t];
if (s[t+1]==j) t++;
map[i][j-MINCHAR]=t+1;
}
}
void calc_dp(int m)
{
int i,j,k,l;
memset(dp,0,sizeof(dp));
dp[0][0]=1;
l=strlen(s);
for(i=0;i<=m-1;i++)
for(j=0;j<=l-1;j++)
for(k='a'-MINCHAR;k<='z'-MINCHAR;k++)
dp[i+1][map[j][k]]+=p[k]*dp[i][j];
}
int main()
{
int n,m,i,j,x,k;
while(scanf("%d %d",&n,&m)!=EOF)
{
if (n==0&&m==0) break;
memset(p,0,sizeof(p));
for(i=1;i<=n;i++)
{
scanf("%s",s);
scanf("%lf",&p[s[0]-MINCHAR]);
}
scanf("%s",s);
get_next(s);
calc_map();
memset(dp,0,sizeof(dp));
dp[0][1]=1;
ans=0;
calc_dp(m);
for(i=1;i<=m;i++)
ans+=dp[i][strlen(s)];
printf("%.2lf%%/n",ans*100);
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: