目录
Time Limit: 1s Memory Limit: 128MB
原题:
Time Limit: 1s Memory Limit: 128MB
Description
某人有一套玩具,并想法给玩具命名。首先他选择四个字母中的任意一个字母作为玩具的基本名字。然后他会根据自己的喜好,将名字中任意一个字母用“”中任意两个字母代替,使得自己的名字能够扩充得很长。现在,他想请你猜猜某一个很长的名字,最初可能是由哪几个字母变形过来的。
Input
第一行四个整数。表示每一个字母能由几种两个字母所替代。接下来行,每行两个字母,表示可以用这两个字母替代。接下来行,每行两个字母,表示可以用这两个字母替代。接下来行,每行两个字母,表示可以用这两个字母替代。接下来行,每行两个字母,表示可以用这两个字母替代。最后一行一个长度不超过的字符串。表示这个玩具的名字。
Output
一行字符串,该名字可能由哪些字母变形而得到。(按照的顺序输出)如果给的名字不能由任何一个字母变形而得到则输出“The name is wrong!”
Sample Input
1 1 1 1
II
WW
WW
IG
IIII
Sample Output
IN
HINT
可以变成所以可以缩成
均能变成所以又可以缩成或者所以最终答案应该按照“”的顺序输出
数据范围
数据满足,、、、
题目大意:
给你一个长度为Len的字符串,让你求它最终可以缩成什么字母。
主要思路:
我们可以用区间dp来做,dp[i][j][ch] 表示从区间[i,j]可以合成一个字母ch(ch是整数,W是1,I是2,N是3,G是4),还要用一个vis[i][j][ch],表示i,j两个字母可以合成一个字母ch(都是整数),用区间dp模板轻松搞定。
注意事项:
- 边界设置问题
- dp的初始化
代码(有注释):
#include<bits/stdc++.h>
using namespace std;
unordered_map<int,char> w;
unordered_map<char,int> mp;//转换
bool vis[10][10][10];
int a[10];
string s;
bool dp[210][210][10];
int main()
{
mp['W'] = 1;
mp['I'] = 2;
mp['N'] = 3;
mp['G'] = 4;
w[1] = 'W';
w[2] = 'I';
w[3] = 'N';
w[4] = 'G';//转换
for(int i=1;i<=4;i++)
{
cin>>a[i];//输入进来
}
for(int i=1;i<=4;i++)
{
for(int j=1;j<=a[i];j++)
{
char c1,c2;
cin>>c1>>c2;
vis[mp[c1]][mp[c2]][i] = 1;//用两个合成一个标记
}
}
cin>>s;
int n=s.size();
for(int i=1;i<=n;i++)
{
dp[i][i][mp[s[i-1]]] = 1;//一个字符肯定可以由这个字符合成的
}
for(int len=2;len<=n;len++)
{
for(int l=1;l+len-1<=n;l++)
{
int r=l+len-1;//基本区间dp模板
for(int k=l;k<=r;k++)//枚举断点
{
for(int c1=1;c1<=4;c1++)
{
for(int c2=1;c2<=4;c2++)
{
for(int c3=1;c3<=4;c3++)//枚举三个字符
{
if(dp[l][k][c2]&&dp[k+1][r][c3]&&vis[c2][c3][c1])//如果区间l~k可以合成c2,k+1~r可以合成c3,c2和c3可以合成c1,那么l~r就可以合成c1。
{
dp[l][r][c1]=1;//标记起来
}
}
}
}
}
}
}
bool flag=1;
for(int i=1;i<=4;i++)
{
if(dp[1][n][i])//如果可以合成
{
cout<<w[i];//输出
flag=0;//去除标记
}
}
if(flag)//如果标记还存在
{
cout<<"The name is wrong!";//就输出错误
}
return 0;
}