Substring UVA - 11468 AC自动机+记忆搜索

 Given a set of pattern strings, and a text, you have to nd, if any of the pattern is a substring of the
text. If any of the pattern string can be found in text, then print `yes', otherwise `no' (without quotes).
But, unfortunately, thats not what is asked here.
The problem described above, requires a input le generator. The generator generates a text of
length L, by choosing L characters randomly. Probability of choosing each character is given as priori,
and independent of choosing others.
Now, given a set of patterns, calculate the probability of a valid program generating \no".

#include 
#include 
#include 
using namespace std;

const int MAX_LEN = 400+5, SIGMA_SIZE = 63; 
double prob[SIGMA_SIZE];
int idx[256]; //形成字符-idx的映射 
int k, n, L;
struct AcAutomata{
	int ch[MAX_LEN][SIGMA_SIZE];
	int f[MAX_LEN]; // failure function 
	int match[MAX_LEN]; //是否包含某一个字符串
	int size;
	
	void init(){
		size = 1;
		memset(ch[0], 0, sizeof(ch[0]));
		memset(vis, 0, sizeof(vis));
	}
	// 插入字符串
	void insert(char *s){
		int u = 0, n = strlen(s);
		for(int i = 0; i < n; i++){
			int c = idx[s[i]];
			if( !ch[u][c]){
				memset(ch[size], 0, sizeof(ch[size]));
				match[size] = 0;
				ch[u][c] = size++;
			}
			u = ch[u][c];
		}
		match[u] = 1; //记录该节点为字符串结尾 
	}
	// 计算fail函数
	void getFail(){
		queue q;
		f[0] = 0;
		for(int c = 0; c < SIGMA_SIZE; c++){
			int u = ch[0][c];
			if(u){
				f[u] = 0;
				q.push(u);
			}
		}		
		while( !q.empty()){
			int r = q.front(); q.pop();
			for(int c = 0; c < SIGMA_SIZE; c++){
				int u = ch[r][c];
				if( !u){
					ch[r][c] = ch[f[r]][c]; //跳转到失效函数的子节点存在则当前节点也应存在(即不能继续组成字符串)。 
					continue;
				} 
				q.push(u);
				int v = f[r];
				while(v && !ch[v][c]) v = f[v];
				f[u] = ch[v][c];
				match[u] |= match[f[u]]; 
			}
		}
	}
	double d[MAX_LEN][105];
	int vis[MAX_LEN][105];
	double getProb(int u,int L){
		if(!L) return 1.0;
		if(vis[u][L]) return d[u][L];
		vis[u][L] = 1;
		double &ans = d[u][L];
		ans = 0;
		for(int i = 0; i < n; i++){
			if( !match[ch[u][i]])
				ans += prob[i] * getProb(ch[u][i], L-1);
		}
		return ans;
	}
};

AcAutomata ac;
const int K = 20+5, LEN = 20+5;
char pattern[K][LEN];

int main(int argc, char** argv) {
	int t, kase = 0;
	scanf("%d",&t);
	while( t--){		
		scanf("%d",&k);
		ac.init();
		for(int i = 0; i < k; i++)
			scanf("%s",&pattern[i]);
		scanf("%d",&n);
		memset(prob, 0, sizeof(prob)); 
		for(int i = 0; i < n; i++){
			char s[9];
			scanf("%s%lf",&s, &prob[i]);
			idx[s[0]] = i;
		}
		for(int i = 0; i < k; i++) 
			ac.insert(pattern[i]);
		ac.getFail();
		scanf("%d",&L);
		printf("Case #%d: %.6lf\n", ++kase, ac.getProb(0,L));
	}
	return 0;
}

Input
First line contains an integer T, the number of test cases. Each case starts with an integer K, the
number of pattern strings. Next K lines each contain a pattern string, followed by an integer N,
number of valid characters. Next N lines each contain a character and the probability of selecting that
character, pi. Next an integer L, the length of the string generated. The generated text can consist of
only the valid characters, given above.
There will be a blank line after each test case.
Output
For each test case, output the number of test case, and the probability of getting a \no".
Constraints:
T 50
K 20
Length of each pattern string is between 1 and 20
Each pattern string consists of only alphanumeric characters (a to z, A to Z, 0 to 9)
Valid characters are all alphanumeric characters

Σ
pi = 1
L 100
Sample Input
2
1
a
2
a 0.5
b 0.5
2
2
ab
ab
2
a 0.2
b 0.8
2
Sample Output
Case #1: 0.250000
Case #2: 0.840000

你可能感兴趣的:(AC自动机,动态规划,算法竞赛入门-训练指南)