[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;
}

  

时间: 2024-10-05 09:41:50

[BZOJ 1055] [HAOI2008] 玩具取名 【记忆化搜索】的相关文章

bzoj 1055 [HAOI2008]玩具取名(区间DP)

1055: [HAOI2008]玩具取名 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1258  Solved: 729[Submit][Status][Discuss] Description 某 人有一套玩具,并想法给玩具命名.首先他选择WING四个字母中的任意一个字母作为玩具的基本名字.然后他会根据自己的喜好,将名字中任意一个字母用 “WING”中任意两个字母代替,使得自己的名字能够扩充得很长.现在,他想请你猜猜某一个很长的名字,最初可能

BZOJ 1055 [HAOI2008]玩具取名

1055: [HAOI2008]玩具取名 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1119  Solved: 653[Submit][Status][Discuss] Description 某人有一套玩具,并想法给玩具命名.首先他选择WING四个字母中的任意一个字母作为玩具的基本名字.然后他会根据自己的喜好,将名字中任意一个字母用“WING”中任意两个字母代替,使得自己的名字能够扩充得很长.现在,他想请你猜猜某一个很长的名字,最初可能是由

[BZOJ 1055][HAOI2008]玩具取名(DP)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1055 分析: 比较难想的dp f[i][j][c]表示i..j能否压缩成字符c 那么怎么转移呢 如果存在i<=k<j,f[i][k][c1]=true且f[k+1][j][c2]=true且c1c2可以压缩成字符c(这个根据读入判断),那么f[i][j][c]就是true. 记忆化搜索比较好实现了.

BZOJ 1055 HAOI2008 玩具取名 动态规划

题目大意:给定一个由'W','I','N','G'构成的字符串,给定一些规则,这些规则可以将两个字符合成为一个,例如"II"可以合成为'W',"WW"可以合成为'I'或者'N' 求这个字符串可以最终合成为哪几种字符 看到这题我想到了广搜...其实没必要,动归完全可以解决 令f[i][j][k]为从i开始的j个字符是否可以合成为字符[k] 然后j从外层循环,剩下的全部预处理,怎么暴力怎么转移,我写了六层循环,有点吓人 #include<cstdio> #i

bzoj 1055 [HAOI2008]玩具取名 区间dp

题面 题目传送门 解法 直接区间dp即可 时间复杂度:\(O(16n^3)\) 代码 #include <bits/stdc++.h> #define N 210 using namespace std; struct Node { int x, y; } a[5][N]; int s[5], p[5][5][5]; bool f[N][N][5], vis[N][N][5]; int num(char ch) { if (ch == 'W') return 1; if (ch == 'I')

BZOJ 1079: [SCOI2008]着色方案 记忆化搜索

1079: [SCOI2008]着色方案 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1079 Description 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块.所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个木块涂相同色显得很难看,所以你希望统计任意两个相邻木块颜色不同的

BZOJ 3895 取石子 博弈论+记忆化搜索

题目大意:给定n堆石子,两人轮流操作,每个人可以合并两堆石子或拿走一个石子,不能操作者输,问是否先手必胜 直接想很难搞,我们不妨来考虑一个特殊情况 假设每堆石子的数量都>1 那么我们定义操作数b为当前石子总数+当前堆数-1 若b为奇数,则先手必胜,否则后手必胜 证明: 若当前只有一堆,则正确性显然 否则: 若b为奇数,那么先手只需进行一次合成操作,此时操作数会-1,且仍不存在大小为1的堆 因此只需要证明b为偶数时先手必败即可 若先手选择了合成操作,那么操作数-1且不存在大小为1的堆,状态回到了b

【BZOJ】1055: [HAOI2008]玩具取名(dp)

http://www.lydsy.com/JudgeOnline/problem.php?id=1055 我竟然都没往dp这个方向想.....百度了下看到标题是dp马上就会转移了QAQ... 设d[i,j,k]表示i~j是否能转移成k. 那么很显然.. d[i,j,k]=d[i,k,x]&&d[k+1,j,y]&&a[k,x,y],a[k,x,y]表示k能转移到xy. 然后我数组小了re..(我都开了202啦........... 然后没有判误解wa了......太sb..

BZOJ1055: [HAOI2008]玩具取名

1055: [HAOI2008]玩具取名 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 820  Solved: 482[Submit][Status] Description 某人有一套玩具,并想法给玩具命名.首先他选择WING四个字母中的任意一个字母作为玩具的基本名字.然后他会根据自己的喜好,将名字中任意一个字母用“WING”中任意两个字母代替,使得自己的名字能够扩充得很长.现在,他想请你猜猜某一个很长的名字,最初可能是由哪几个字母变形过来的