您的位置:首页 > 其它

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

2018-03-13 20:44 435 查看

传送门

戳戳戳

题解

貌似我就没写过几道区间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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: