bzoj1055 [HAOI2008]玩具取名(区间)

Description

  某人有一套玩具,并想法给玩具命名。首先他选择WING四个字母中的任意一个字母作为玩具的基本名字。然后
他会根据自己的喜好,将名字中任意一个字母用“WING”中任意两个字母代替,使得自己的名字能够扩充得很长。
现在,他想请你猜猜某一个很长的名字,最初可能是由哪几个字母变形过来的。
Input

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

  一行字符串,该名字可能由哪些字母变形而得到。(按照WING的顺序输出)如果给的名字不能由任何一个字母
变形而得到则输出“The name is wrong!”

Sample Input
1 1 1 1
II
WW
WW
IG
IIII

Sample Output
IN

分析:
1A✿✿ヽ(°▽°)ノ✿
说白了,就是一道合并游戏
诶。。。好像是石子合并的加强版
f[i][j][0/1/2/3]
表示从i到j的字符串能不能替换成WING

tip

对于状态的处理注意一下
直接把字母转化成了数字,计入zt(zhuangtai)数组

int get(char a)
{
    if (a=='W') return 0;
    else if (a=='I') return 1;
    else if (a=='N') return 2;
    else return 3;
}

void cl(int bh,int z)
{
    int x,y;
    x=get(w[0]);
    y=get(w[1]); 
    zt[bh][z][0]=x;
    zt[bh][z][1]=y;
}

在转移的时候
这里写图片描述
注意 if (!f[i][j][0]) 的判断,
不然会出现明明这个状态可以通过一种方式到达,
但是另一种方式到达不了,导致f[i][j][]状态能否到达判断失误

因为只是一个判定性的问题,所以这里f的类型我定义的是bool
节省空间(没这个必要,但要养成节约的好习惯)

这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

const int nn=210;
char s[nn],w[5];
int W,I,N,G;
int mp[5][5],zt[5][20][2];
bool f[nn][nn][5],flag=0;

int get(char a)
{
    if (a=='W') return 0;
    else if (a=='I') return 1;
    else if (a=='N') return 2;
    else return 3;
}

void cl(int bh,int z)
{
    int x,y;
    x=get(w[0]);
    y=get(w[1]); 
    zt[bh][z][0]=x;
    zt[bh][z][1]=y;
}

void doit()
{
    int i,j,k,q,r1,r2;
    int l=strlen(s);
    for (i=0;i<l;i++)
         f[i][i][get(s[i])]=1;
    for (i=l-2;i>=0;i--)
        for (j=i+1;j<l;j++)
            for (k=i;k<j;k++)
            {
                for (q=1;q<=W;q++) 
                {
                    r1=zt[0][q][0];r2=zt[0][q][1];  //两个可以转移的字母 
                    if (!f[i][j][0]) f[i][j][0]=f[i][k][r1]&f[k+1][j][r2];
                }
                for (q=1;q<=I;q++) 
                {
                    r1=zt[1][q][0];r2=zt[1][q][1];  //两个可以转移的字母 
                    if (!f[i][j][1]) f[i][j][1]=f[i][k][r1]&f[k+1][j][r2];
                }
                for (q=1;q<=N;q++) 
                {
                    r1=zt[2][q][0];r2=zt[2][q][1];  //两个可以转移的字母 
                    if (!f[i][j][2]) f[i][j][2]=f[i][k][r1]&f[k+1][j][r2];
                }
                for (q=1;q<=G;q++) 
                {
                    r1=zt[3][q][0];r2=zt[3][q][1];  //两个可以转移的字母 
                    if (!f[i][j][3]) f[i][j][3]=f[i][k][r1]&f[k+1][j][r2];
                }
            }
    if (f[0][l-1][0]) printf("W"),flag=1;
    if (f[0][l-1][1]) printf("I"),flag=1;
    if (f[0][l-1][2]) printf("N"),flag=1;
    if (f[0][l-1][3]) printf("G"),flag=1;
    if (!flag) printf("The name is wrong!");
}

int main()
{
    memset(f,0,sizeof(f));
    scanf("%d%d%d%d",&W,&I,&N,&G);
    for (int i=1;i<=W;i++){scanf("%s",&w);cl(0,i);} 
    for (int i=1;i<=I;i++){scanf("%s",&w);cl(1,i);} 
    for (int i=1;i<=N;i++){scanf("%s",&w);cl(2,i);} 
    for (int i=1;i<=G;i++){scanf("%s",&w);cl(3,i);} 
    scanf("%s",&s);
    doit();
    return 0;
} 
原文地址:https://www.cnblogs.com/wutongtong3117/p/7673455.html