传送门
题解
貌似我就没写过几道区间DP的题,好像除了石子合并和某四边形优化果题就没了。。
这题要求让连续的一段缩起来,而且长的能不能缩取决于短的缩出来的是什么。于是这就是一个区间DP了。
设dp[x][l][r]表示从l到r缩成x是否可行。我们枚举中间点k和操作就可以转移了。区间DP的k的取值一般是左闭右开的,我又回忆起来了。嗯。
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#define maxn 222
using namespace std;
char s[5], S[maxn];
int a[maxn], b[maxn], c[maxn];
int n1, n2, n3, n4, n, len;
bool dp[maxn][maxn][maxn];
int main(){
scanf("%d%d%d%d", &n1, &n2, &n3, &n4);
n = n1 + n2 + n3 + n4;
for(int i = 1; i <= n; i++){
scanf("%s", s);
a[i] = s[0]-'A';
b[i] = s[1]-'A';
if(i <= n1) c[i] = 'W'-'A';
else if(i <= n1+n2) c[i] = 'I'-'A';
else if(i <= n1+n2+n3) c[i] = 'N'-'A';
else c[i] = 'G'-'A';
}
scanf("%s", S);
len = strlen(S);
for(int i = 1; i <= len; i++)
dp[S[i-1]-'A'][i][i] = true;
for(int l = 2; l <= len; l++)
for(int i = 1; i <= len-l+1; i++){
int j = i + l - 1;
for(int k = i; k < j; k++)
for(int p = 1; p <= n; p++)
dp[c[p]][i][j] |= dp[a[p]][i][k] && dp[b[p]][k+1][j];
}
bool WY = false;
if(dp['W'-'A'][1][len]) putchar('W'), WY = true;
if(dp['I'-'A'][1][len]) putchar('I'), WY = true;
if(dp['N'-'A'][1][len]) putchar('N'), WY = true;
if(dp['G'-'A'][1][len]) putchar('G'), WY = true;
if(!WY) puts("The name is wrong!");
return 0;
}