题目描述
已知有两个字串 A, B 及一组字串变换的规则(至多6个规则):
A1 -> B1
A2 -> B2
规则的含义为:在 A$中的子串 A1 可以变换为 B1、A2 可以变换为 B2 …。
例如:A='abcd'B='xyz'
变换规则为:
‘abc’->‘xu’‘ud’->‘y’‘y’->‘yz’
则此时,A 可以经过一系列的变换变为 B,其变换的过程为:
‘abcd’->‘xud’->‘xy’->‘xyz’
共进行了三次变换,使得 A 变换为B。
输入输出格式
输入格式:
键盘输人文件名。文件格式如下:
A B A1 B1 \
A2 B2 |-> 变换规则
... ... /
所有字符串长度的上限为 20。
输出格式:
输出至屏幕。格式如下:
若在 10 步(包含 10步)以内能将 A 变换为 B ,则输出最少的变换步数;否则输出"NO ANSWER!"
输入输出样例
abcd xyz abc xu ud y y yz
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bfs+字符串~
刷新世界观的神题……
(1)队列要建成string型的;
(2)map还可以当做记录状态的数组来用;
(3)队列还有find,replace等等神奇的操作;
(4)不定项输入用scanf可能会RE,cin实在强大;
(5)这题是没法在本机调试的,只能在OJ上交后再改错,帮我迅速拉低正确率……
这道题用到了类似bfs的算法。
把目标串和初始串分别加入队列中,每次双向更新并记录可以更新到的字符串以及其改变次数,直到某一队列中更新出另一队列曾更新出的结果,就直接输出,因为此时的解一定是最优的。
(输出结果要-2,因为刚开始为了区分是否更新过,初始两串都记为度1。)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<map>
using namespace std;
int n,len;
queue<string> qa,qb;
string a,b,s1[21],s2[21];
map<string,int> ba,bb;
int main()
{
cin>>a>>b;n=1;
while(cin>>s1[n]>>s2[n]) n++;n--;
ba[a]=1;bb[b]=1;qa.push(a);qb.push(b);
while(1)
{
if(qa.empty() || qb.empty())
{
printf("NO ANSWER!\n");return 0;
}
string nowa=qa.front(),nowb=qb.front();
for(int i=1;i<=n;i++)
{
int kkz=0;
while((kkz=nowa.find(s1[i],kkz))!=-1)
{
len=s1[i].size();
nowa.replace(kkz,len,s2[i]);
if(!ba[nowa])
{
ba[nowa]=ba[qa.front()]+1;qa.push(nowa);
}
if(bb[nowa])
{
printf("%d\n",ba[nowa]+bb[nowa]-2);return 0;
}
kkz++;
nowa=qa.front();
}
kkz=0;
while((kkz=nowb.find(s2[i],kkz))!=-1)
{
len=s2[i].size();
nowb.replace(kkz,len,s1[i]);
if(!bb[nowb])
{
bb[nowb]=bb[qb.front()]+1;qb.push(nowb);
}
if(ba[nowb])
{
printf("%d\n",bb[nowb]+ba[nowb]-2);return 0;
}
kkz++;
nowb=qb.front();
}
}
qa.pop();qb.pop();
}
}