https://www.luogu.org/problemnew/show/P1032
题目描述
已知有两个字串A,BA,B及一组字串变换的规则(至多66个规则):
A 1-> B 1
A 2 -> B 2
规则的含义为:在 A中的子串A 1
可以变换为 B 1,A 2可以变换为B 2
…。
例如:A='abcd'B='xyz'
变换规则为:
‘abc’->‘xu’‘ud’->‘y’‘y’->‘yz’
则此时,A可以经过一系列的变换变为B,其变换的过程为:
‘abcd’->‘xud’->‘xy’->‘xyz’
共进行了3次变换,使得AA变换为BB。
输入输出格式
输入格式:
输入格式如下:
AA BB
A 1 B 1
A 2 B 2
|-> 变换规则
… … /
所有字符串长度的上限为20。
输出格式:
输出至屏幕。格式如下:
若在10步(包含10步)以内能将A变换为B,则输出最少的变换步数;否则输出"NO ANSWER!"
输入输出样例
输入样例#1:
abcd xyz
abc xu
ud y
y yz
输出样例#1:
3
ac_code:
/*
每个点是一个字符串,想到用map标记~
之前用dfs做只有60分,然后第一次用bfs做80分,最后组数据WA
WA的点就是,没有考虑到一个串对于一种转换规则可能会有多个位置可变,而他们都是1步到达:
比如:
aacadb abcdef(原串,目标串)
a b(其中一条转换规则)
一步就可以得到:
bacadb
abcadb
aacbdb
所以对于原串不是找到一处匹配的就变换后进行下个规则
而是继续对于这个规则找找看一下有没有其他地方可以匹配
so对于查询是否有可以使用转换规则时要用while
还有对于输入,它规则个数是不确定的,可以用ctrl+z结束输入,但是要记录到底用多少条规则
*/
#include <iostream>
#include <string>
#include <queue>
#include <map>
using namespace std;
struct rules
{
string A;
string B;
int len_a;
} data[10];
string s,e;
int cnt;
map<string,bool>vis;
map<string,int>step;
int bfs()
{
queue<string>q;
q.push(s);
vis[s] = true;
while(!q.empty())
{
string k = q.front();
if(step[k] > 10)
{
break;
}
q.pop();
if(k == e)
{
return step[k];
}
for(int i = 0; i < cnt; i++)
{
int pos = -1;
//string t = k; //如果要直接用replace要先记录下原串
while(k.find(data[i].A,pos+1)!=string::npos)
{
pos = k.find(data[i].A,pos+1);
//cout<<pos<<endl;
if(pos != -1)
{
string s1 = k.substr(0,pos);
int t = pos + data[i].len_a;
string s2 = k.substr(t,k.length()-t);
string now = s1 + data[i].B + s2;
//string now = k.replace(pos,data[i].len_a,data[i].B);//replace会使原串改变
//k = t;
//cout<<now<<" "<<k<<endl;
if(!vis[now])
{
vis[now] = true;
step[now] = step[k] + 1;
q.push(now);
}
}
}
}
}
return -1;
}
int main()
{
cin>>s>>e;
for(int i = 0; i < 6; i++)
{
cin>>data[i].A>>data[i].B;
data[i].len_a = data[i].A.length();
if(data[i].A == "\0")
break;
else cnt++;
}
int ans = bfs();
if(ans != -1)
cout<<ans<<endl;
else
cout<<"NO ANSWER!"<<endl;
return 0;
}