[HAOI2008]玩具取名

[HAOI2008]玩具取名

标签:动态规划 区间DP


题目描述

某人有一套玩具,并想法给玩具命名。首先他选择WING四个字母中的任意一个字母作为玩具的基本名字。然后他会根据自己的喜好,将名字中任意一个字母用“WING”中任意两个字母代替,使得自己的名字能够扩充得很长。

现在,他想请你猜猜某一个很长的名字,最初可能是由哪几个字母变形过来的。

输入输出格式

输入格式

第一行四个整数W、I、N、G。表示每一个字母能由几种两个字母所替代。
接下来W行,每行两个字母,表示W可以用这两个字母替代。
接下来I行,每行两个字母,表示I可以用这两个字母替代。
接下来N行,每行两个字母,表示N可以用这两个字母替代。
接下来G行,每行两个字母,表示G可以用这两个字母替代。
最后一行一个长度不超过Len的字符串。表示这个玩具的名字。

输出格式

一行字符串,该名字可能由哪些字母变形而得到。(按照WING的顺序输出)

如果给的名字不能由任何一个字母变形而得到则输出“The name is wrong!”

样例

输入样例#1:
1 1 1 1
II
WW
WW
IG
IIII
输出样例#1:
IN

Hint

30%数据满足Len<=20,W、I、N、G<=6
100%数据满足Len<=200,W、I、N、G<=16

题解

题意是由一个字母变成一段字母区间,问这个字母是什么。那我们不妨反过来思考,这一段区间能否变成一个字母。状态也就随之而来了。
f[i][j][k]表示[i,j]这段区间是否可以合成k这个字符。
转移肯定采用区间合并法。
小trick:在读入的是否我们可以用一个g[i][j][k]数组表示i字符和j字符能否组成k字符。
转移方程:

for(int k = i; k < j; k ++) //枚举断点
    for(int a = 1; a <= 4; a ++) //枚举字符
        for(int b = 1; b <= 4; b ++) //枚举字符
            for(int c = 1; c <= 4; c ++) //枚举字符
                if(g[a][b][c] && f[i][k][b] && f[k + 1][j][c]) //如果全部合法,则可以转移
                  f[i][j][a] = true;

代码

#include<bits/stdc++.h>
#define N 210
#define M 20
using namespace std;

char s[N], c[5] = {'K', 'W', 'I', 'N', 'G'};
int a[N];
bool f[N][N][M], g[N][N][M];

int modify(char x)
{
    if(x == 'W') return 1;
    if(x == 'I') return 2;
    if(x == 'N') return 3;
    if(x == 'G') return 4;
}

int main()
{
    for(int i = 1; i <= 4; i ++)
        scanf("%d", &a[i]);
    for(int i = 1; i <= 4; i ++)
        for(int j = 1; j <= a[i]; j ++)
        {
            scanf("%s", s);
            g[i][modify(s[0])][modify(s[1])] = true;
        }
    scanf("%s", s + 1);
    int n = strlen(s + 1);
    for(int i = 1; i <= n; i ++)
        f[i][i][modify(s[i])] = true;
    for(int l = 1; l <= n; l ++)
        for(int i = 1; i <= n - l + 1; i ++)
        {
            int j = l + i - 1;
            for(int k = i; k < j; k ++)
                for(int a = 1; a <= 4; a ++)
                    for(int b = 1; b <= 4; b ++)
                        for(int c = 1; c <= 4; c ++)
                            if(g[a][b][c] && f[i][k][b] && f[k + 1][j][c])
                               f[i][j][a] = true;
        }
    bool flag = false;
    for(int i = 1; i <= 4; i ++)
        if(f[1][n][i]) printf("%c", c[i]), flag = true;
    if(!flag) printf("The name is wrong!");
    return 0;
} 

心得

有时候逆向思考问题会得到不错的想法啊。


 上一篇
Outer space invaders Outer space invaders
[CERC2014]Outer space invaders标签:动态规划 区间DP 题目描述题目描述 来自外太空的外星人(最终)入侵了地球。保卫自己,或者解体,被他们同化,或者成为食物。迄今为止,我们无法确定。外星人遵循已知的攻击模式。
2019-05-22
下一篇 
String painter String painter
String painter标签: 区间DP 题目描述There are two strings A and B with equal length. Both strings are made up of lower case lett
2019-05-20