1055: [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

HINT

W可以变成II所以IIII可以缩成WW IN均能变成WW所以WW又可以缩成I或者N 所以最终答案应该按照“WING”的顺序

输出IN 

[数据范围]
100%数据满足Len<=200,W、I、N、G<=16
题解:实话说,看题目时连设都不会设,网上的题解对我来说又太过简洁,还是在老师的教导下才听懂的。。。(唉,有我这种学生真的是麻烦老师了)。
进入主题,因为c++中的数组不能用字符,所以我们用1表示‘W’,2表示‘I’,以此类推到4.
方程式中用f[i][j][k]来表示i到j的这段区间内能否表示为k,具体的话不太容易空讲,所以看程序注释吧!
程序:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string>
using namespace std;
int m,n,a,b,ans,c,d,q,r,w[100][4];
char ch1,ch2;
bool f[300][300][5];
string s,s1;
int main()
{
cin>>a>>b>>c>>d;
for (int i=1;i<=a+b+c+d;i++) 
//这里我们用一个w数组来储存读入的元素,举个例子,现在w可转换为IG,那么w[i][1]储存I,w[i][2]储存G,w[i][3]则储存w,i的取值由这两个字母是第几个被输入的决定。 if (i>a+b+c) w[i][3]=4; else if (i>a+b) w[i][3]=3; else if (i>a) w[i][3]=2; else w[i][3]=1; cin>>s1; ch1=s1[0]; ch2=s1[1]; if (ch1=='W') w[i][1]=1; else if (ch1=='I') w[i][1]=2;else if (ch1=='N') w[i][1]=3;else if (ch1=='G') w[i][1]=4; if (ch2=='W') w[i][2]=1; else if (ch2=='I') w[i][2]=2;else if (ch2=='N') w[i][2]=3;else if (ch2=='G') w[i][2]=4; } cin>>s; n=s.size(); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) for (int k=1;k<=4;k++) f[i][j][k]=false; //f[i][j][k]表示这段区间内能否由k转换而来。先全都初始化。 for (int i=0;i<=n-1;i++)//原先序列中有的先赋值为true,i从0开始是因为c++中字符串中的第一个字符储存在0号位中。 { if (s[i]=='W') f[i+1][i+1][1]=true; else if (s[i]=='I') f[i+1][i+1][2]=true; else if (s[i]=='N') f[i+1][i+1][3]=true; else if (s[i]=='G') f[i+1][i+1][4]=true; } for (int len=2;len<=n;len++)//枚举区间长度 for (int i=1;i<=n-len+1;i++)//区间左边 { r=i+len-1;//区间右边 m=i;//我们通过m把区间分为两部分 while (m<=r-1)//枚举m { for (int k=1;k<=a+b+c+d;k++)//枚举那些转换公式 f[i][r][w[k][3]]=(f[i][m][w[k][1]])&&(f[m+1][r][w[k][2]])||(f[i][r][w[k][3]]);

//核心部分,我们去判断由m分开的区间左部分和右部分,是否刚好可以转换成w[k]这个公式的左边字母和右边字母,(即两边都为TRUE)
若可以,那么这个区间就可以是w[k][3]中的字母转换而来,赋值为TRUE。
m+=1; } } ans=0; for (int i=1;i<=4;i++) if (f[1][n][i]==true) //按顺序输出 { if (i==1) printf("W"); if (i==2) printf("I"); if (i==3) printf("N"); if (i==4) printf("G"); ans+=1;//记录是否有答案 } if (ans==0) printf("The name is wrong!");//没答案 return 0; }

唔,复杂度是O(200^3*64),不知是因为实际上没有200^3,还是数据水,还是写着10s的原因,很险地过了。。。。

原文地址:https://www.cnblogs.com/2014nhc/p/6231373.html