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;
}
标签:opt,ch,return,int,压缩成,取名,玩具,P4290,change 来源: https://www.cnblogs.com/xqk0225/p/16177207.html