Java教程

P4290 玩具取名

本文主要是介绍P4290 玩具取名,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

感谢所有AC

传送门

思路

       一道求解存在性的区间dp,思路非常巧妙。对于原名字串,通过压缩变换,如果最后能够压缩成单个字母则该字母为一个答案。

       如何实现压缩的过程?设计状态 $f(i,j,k)$ 为原串从位置 $i$ 到位置 $j$ 压缩成 $k$ 的可能性。$opt(l,r,t)$ 为 $l$ 和 $r$ 压缩成t的可能性,$opt$ 状态用来存储变换规则。同时,为了方便表示,把四个字母转化成数字。

       转移方程为 $f(i,j,k) = f(i,d,x)\ \&\& \ f(d+1,j,y)\ \&\& \ opt(x,y,k)$ 形式上也是比较好理解的,两个字母压缩成一个字母,只要一个条件不存在,整个转移不存在。但是需要注意的是,如果不对三个条件进行判断,需要在转移时加上或运算符。因为可能出现一个压缩在第一次转移时判断为存在,但是在第二次转移时由于条件不符合而被判断为不存在。

代码

#include<iostream>
#include<cstring>
using namespace std;
int W, I, N, G;
string ch;
bool opt[10][10][10], f[205][205][205], flag;
int change(char ch)
{
	if (ch == 'W')return 1;
	if (ch == 'I')return 2;
	if (ch == 'N')return 3;
	if (ch == 'G')return 4;
}
int main(void)
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cin >> W >> I >> N >> G;
	for (int i = 1; i <= W; i++)
		cin >> ch, opt[change(ch[0])][change(ch[1])][1] = 1;
	for (int i = 1; i <= I; i++)
		cin >> ch, opt[change(ch[0])][change(ch[1])][2] = 1; 
	for (int i = 1; i <= N; i++)
		cin >> ch, opt[change(ch[0])][change(ch[1])][3] = 1;
	for (int i = 1; i <= G; i++)
		cin >> ch, opt[change(ch[0])][change(ch[1])][4] = 1;
	cin >> ch;
	for (int i = 1; i <= ch.size(); i++)
		f[i][i][change(ch[i - 1])] = 1;
	for (int L = 2; L <= ch.size(); L++)
		for (int i = 1, j = i + L - 1; j <= ch.size(); i++, j++)
			for (int k = i; k < j; k++)
				for (int r = 1; r <= 4; r++)
					for (int x = 1; x <= 4; x++)
						for (int y = 1; y <= 4; y++)
							f[i][j][r] |= (f[i][k][x] && f[k + 1][j][y] && opt[x][y][r]);
	if (f[1][ch.size()][1])cout << 'W', flag = 1;
	if (f[1][ch.size()][2])cout << 'I', flag = 1;
	if (f[1][ch.size()][3])cout << 'N', flag = 1;
	if (f[1][ch.size()][4])cout << 'G', flag = 1;
	if (!flag)cout << "The name is wrong!" << endl;
	return 0;
}

 

这篇关于P4290 玩具取名的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!