Title: http://acm.whu.edu.cn/land/problem/detail?problem_id=1572
Test instructions: There are n target string, the length is less than four, (n<=8), now randomly write a string length of L, asked to write this string contains the target string of the expected number.
The game was thought to be a water problem, in fact, they are too water. This kind of problem is generally the medium problem of AC automata, the subject can also be done with KMP, combined with pressure DP.
Method one: AC automatic machine
After the completion of the trie tree, is to run the DP, note that the word node to |= (1<<val), there will be a heavy string.
DP process: With DP[I][J][K] in the Automaton node I, the current remaining J step, has a State of K (k is a binary number) probability.
The transfer is the enumeration of the next character, and the current I point will follow the next array toward now= Next[i][ch]
dp[now][j-1][K|end[now]] + = dp[i][j][k] * (1.0/26)
The last statistic will do.
Code:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include < queue>using namespace Std;const int max_n = 105;const int ALP = 26;const int N = 15;struct trie{int Next[max_n][alp ], Fail[max_n], end[max_n]; int root, L; int NewNode () {for (int i=0;i<alp;i++) Next[l][i] =-1; end[l++] = 0; return L-1; } void Init () {memset (end,0,sizeof (end)); L = 0; root = NewNode (); } void Insert (char* buf, int id) {int now = root; int len = strlen (BUF); for (int i=0;i<len;i++) {int ch = buf[i]-' a '; if (next[now][ch]==-1) next[now][ch] = NewNode (); now = Next[now][ch]; } End[now] |= 1<< (id-1); } void Build () {queue<int> Q; Fail[root] = root; for (int i=0;i<alp;i++) if (next[root][i]==-1) next[root][i] = root; else{ Fail[next[root][i]] = root; Q.push (Next[root][i]); } while (! Q.empty ()) {int now = Q.front (); Q.pop (); for (int i=0;i<alp;i++) {if (next[now][i]==-1) next[now][i] = Next[fail[now]][i]; else{Fail[next[now][i]] = next[fail[now]][i]; Q.push (Next[now][i]); }}}} double dp[max_n][n][(1<<8) +5]; Double Get_ans (int n,int step) {for (int i=step;i>=0;i--) for (int. j=0;j<l;j++) for (int k=0;k< (1<<n); k++) dp[j][i][k] = 0; Dp[0][step][0] = 1.0; for (int i=step;i>=1;i--) for (int. j=0;j<l;j++) for (int k=0;k< (1<<n); k++) if (dp[j][i][k]>0) for (int. p=0;p<26;p++) {int now = next[j][p]; int state = 0; int tmp = now; while (tmp!=root) {State |= end[tmp]; TMP = fail[tmp]; } Dp[now][i-1][k|state] + = dp[j][i][k]* (1.0/26); } double ret = 0; for (int i=0;i<l;i++) for (int k=1;k< (1<<n); k++) if (dp[i][0][k]>0) {int EP = 0; for (int p=0;p<n;p++) if (k& (1<<p)) ep++;//printf ("Node%d state%d num%d p=%f\n", I , K,ep,dp[i][0][k]); RET + = Ep*dp[i][0][k]; } return ret; }}ac;char S[15];int Main () {int t,n,l; Cin >> T; while (t--) {scanf ("%d%d", &n,&l); Ac.init (); for (int i=1;i<=n;i++) {scanf ("%s", s); Ac.insert (S,i); } ac.build ();//printf ("numl =%d n L%d%d\n", AC. L,N,L); Double ans = ac.get_ans (n,l); printf ("%.6f\n", ans); } return 0;}
-----------------------------------------------------
Method Two: KMP
Since each target string is independent, it is possible to count the expectations of each target string separately and accumulate.
So for a single string only to get the probability that cannot contain it, its contribution is 1-p.
Also dp:dp[i][j] indicates that the match to the I-bit (I did not match successfully) also has the remaining J step, which cannot contain the probability of this string.
The shift is to enumerate the next character, along the fail function to the next position in the maximum match position now
DP[NOW][J] + = dp[i][j] * (1.0/26)
Statistical contributions and for each goal string.
Code:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm>using namespace std;const int max_n = 20;struct kmp{char p[max_n]; int Fail[max_n],len; void Get_fail () {len = strlen (P); Fail[0] = fail[1] = 0; for (int i=1;i<len;i++) {int j = fail[i]; while (J && p[j]!=p[i]) j = fail[j]; FAIL[I+1] = P[j]==p[i]? j+1:0; }} double dp[max_n][15]; Double Get_ans (int L) {memset (dp,0,sizeof (DP)); DP[0][L] = 1.0; for (int i=l;i>=1;i--) for (int j=0;j<len;j++) {for (int k=0;k<26;k++) {if (j==len-1 && p[len-1]== ' a ' +k) continue; int now = j; if (p[j]== ' a ' +k) now = j+1; else{while (now && p[now]!= ' a ' +k) now = Fail[now]; if (p[now]== ' a ' +k) now++; } Dp[now][i-1] + = dp[j][i]* (1.0/26); }} double ans = 1.0; for (int i=0;i<len;i++) ans-= dp[i][0]; return ans; }}km;int Main () {int t,n,l; Cin >> T; while (t--) {scanf ("%d%d", &n,&l); Double ans = 0; for (int i=1;i<=n;i++) {scanf ('%s '), KM. P); Km.get_fail (); Ans + = Km.get_ans (L); } printf ("%.6f\n", ans); } return 0;}
Through this problem or more in-depth understanding of the KMP and AC automata.
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
woj1572 Cyy and Fzz kmp/ac automata + DP