题目描述
已知有两个字串 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!"
输入样例#1:
abcd xyz
abc xu
ud y
y yz
输出样例#1:
3
题解
其实这道题目数据并不是很强,
所以直接暴力枚举即可(NOIP良心题目)
(如果数据很强的话是不是要用AC自动机???)
每次枚举当前串
枚举每一种变幻方案
查询是否可行
然后变幻一下,放到队列之中继续广搜
(用广搜是很明显的,因为要求最小步数)
判重可以使用map(C++STL真好用)
而对于变幻后字符串的拼接可以使用string中的substr就会非常方便
其他的细节可以看代码(以后这题可能会更新写法)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<algorithm>
using namespace std;
#define MAX 5000
struct Node
{
string s;
int st;
};
map<string,int> M;
string A,B,a[MAX],b[MAX];
int n=0;
queue<Node> Q;
int cnt=1;
int main()
{
cin>>A;cin>>B;
while(cin>>a[++n])
cin>>b[n];
n--;
M[A]=0;
Q.push((Node){A,0});
while(!Q.empty())
{
string s=Q.front().s;
int St=Q.front().st,l=s.length();
if(St==11)break;
Q.pop();
for(int i=1;i<=n;++i)//检查所有规则
{
int l2=a[i].length();
for(int j=0;j<=l-l2;++j)
{
if(s.substr(j,l2)==a[i])//匹配规则
{
string ss;ss.clear();
if(j!=0)ss+=s.substr(0,j);
ss+=b[i];
if(j+l2<l)ss+=s.substr(j+l2,l-l2-j+1);//拼合
if(M.find(ss)==M.end())//没有被用过
{
M[ss]=St+1;
Q.push((Node){ss,St+1});
}
if(ss==B)//找到结果
{
cout<<St+1<<endl;
return 0;
}
}
}
}
}
cout<<"NO ANSWER!"<<endl;
return 0;
}