题目描述
已知有两个字串A,BA,B及一组字串变换的规则(至多66个规则):
A_1A1 ->B_1B1
A_2A2 -> B_2B2
规则的含义为:在 AA中的子串 A_1A1 可以变换为B_1B1,A_2A2 可以变换为 B_2B2 …。
例如:AA='abcdabcd'BB='xyzxyz'
变换规则为:
‘abcabc’->‘xuxu’‘udud’->‘yy’‘yy’->‘yzyz’
则此时,AA可以经过一系列的变换变为BB,其变换的过程为:
‘abcdabcd’->‘xudxud’->‘xyxy’->‘xyzxyz’
共进行了33次变换,使得AA变换为BB。
输入格式:
AA BB
A_1A1 B_1B1
A_2A2 B_2B2 |-> 变换规则
... ... /
所有字符串长度的上限为2020。
输出格式:
若在1010步(包含1010步)以内能将AA变换为BB,则输出最少的变换步数;否则输出"NO ANSWER!"
输入输出样例
输入样例#1:
abcd xyz
abc xu
ud y
y yz
输出样例#1:
3
思路:
直接用广度优先搜索(BFS)来做,加上用set来判重,具体看代码
代码
#include <iostream>
#include <set>
#include <queue>
#include <cstring>
using namespace std;
string a,b,s[10],e[10];
int x=1,p=1;//x:记录变化规则数量 p:特判
struct node{
string a;//字符串
int sum;//已经变化次数
};
queue<node> que;
set<string> mark;//用来判重,否则会TLE在第3点和第5点
void bfs()//重点
{
if(a==b)
{
cout<<"0"<<endl;
return;
}
node t={a,0};
que.push(t);
mark.insert(a);
while(!que.empty())
{
node front=que.front();
que.pop();
if(front.sum>20)
{
cout<<"NO ANSWER!"<<endl;
p=0;
return;
}
for(int i=1;i<=x;i++)
{
int v=0;
//找出所有符合字符串入队
while(1)
{
//找出符合条件的位置
v=front.a.find(s[i],v);
//判断是否找到符合的条件 string::npos==-1
if(v!=string::npos)
{
//合并新串
string newstr=front.a.substr(0,v)+e[i]+front.a.substr(v+strlen(s[i].c_str()));
//根据题目字符串最长20
if(strlen(newstr.c_str())>20){v++;continue;}
//相等直接输出结果
if(newstr==b)
{
cout<<front.sum+1<<endl;
p=0;
return;
}
//判重,重复的串不再入队
if(mark.find(newstr)==mark.end())
{
mark.insert(newstr);
node newnode={newstr,front.sum+1};
que.push(newnode);
}
//从下一个位置开始找
v++;
}
else
{
break;
}
}
}
}
//还有一种情况:变化次数少于20且没有正确答案
if(p)cout<<"NO ANSWER!"<<endl;
return;
}
int main()
{
cin>>a>>b;
while(cin>>s[x]>>e[x])x++;
bfs();
return 0;
}