首页 > 代码库 > [BZOJ 1055] [HAOI2008] 玩具取名 【记忆化搜索】

[BZOJ 1055] [HAOI2008] 玩具取名 【记忆化搜索】

题目链接:BZOJ - 1055

 

题目分析

这种类似区间 DP 的记忆化搜索都是很相近的,比如字符串压缩和字符串扩展都差不多。

都是将现在 Solve 的区间分成子区间,再求解子区间。

这道题 Solve(l, r, x) 求能否将 [l, r] 的区间还原成 x ,那么就将它分成两段,看是否能左段变成 p , 右段变成 q。 (x 能变成 pq)

 

代码

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <algorithm>using namespace std;const int MaxL = 200 + 5;char Ch[5] = {‘W‘, ‘I‘, ‘N‘, ‘G‘};int len;int n[5], f[MaxL][MaxL][5];char S[MaxL];bool Tr[5][5][5];int Solve(int l, int r, int x) {	if (f[l][r][x] != 0) return f[l][r][x];	if (l == r) {		if (S[l] == Ch[x]) {			f[l][r][x] = 1; return 1;		}		else {			f[l][r][x] = -1; return -1;		}	}	for (int i = l; i <= r - 1; ++i) {		for (int j = 0; j < 4; ++j) {			for (int k = 0; k < 4; ++k) {				if (!Tr[x][j][k]) continue;				if (Solve(l, i, j) == 1 && Solve(i + 1, r, k) == 1) {					f[l][r][x] = 1; return 1;				}			}		}	}	f[l][r][x] = -1; return -1;}int GetNum(char c) {	for (int i = 0; i < 4; ++i) 		if (c == Ch[i]) return i;	return -1;}int main() {	for (int i = 0; i < 4; ++i) scanf("%d", &n[i]);	char cc[3];	for (int i = 0; i < 4; ++i) {		for (int j = 1; j <= n[i]; ++j) {			scanf("%s", cc);			Tr[i][GetNum(cc[0])][GetNum(cc[1])] = true;		}	}	scanf("%s", S + 1); len = strlen(S + 1);	bool Flag = false;	for (int i = 0; i < 4; ++i) 		if (Solve(1, len, i) == 1) {			printf("%c", Ch[i]);			Flag = true;		}	if (!Flag) printf("The name is wrong!");	printf("\n");		return 0;}

  

[BZOJ 1055] [HAOI2008] 玩具取名 【记忆化搜索】