题目描述
已知有两个字串 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:
View Code
3
这个题目我一开始根本不知道怎么做...想起来cf有个c题跟这个题面好像(其实很不一样)这个题其实也是搜索,只不过路径变成了字符串的形式转换。做法其实就是把母串(a)从第一个字符开始bfs,思路很简单,但是需要注意的不少,首先是字符串的处理,在学了一堆string的操作函数之后,变换字符串容易多了;然后就是优化时间,因为如果母串里有重复的一段子串,那么它们分别进入队列bfs后,就会出现走出重复路径的现象,所以在同一位置的某一子串只需要变化一次就够了,然后又有map这个容器,可以把string和访问次数对应起来,访问过的子串就不再访问了。据说这个题目可以用双向bfs 可是感觉这样连b串都需要转换一下...太复杂了...就放弃了(其实是嫌麻烦)
#include<bits/stdc++.h> using namespace std; int n,ans; string a,b; string x[25],y[25]; map<string,int>vis; struct node { string t; int step; }; string convert(const string &s,int pos,int k) //按运算规则转换母串 { string temp=""; if(s.length()<pos+x[k].length()) return temp; for(int i=0; i<x[k].length(); i++) { if(s[pos+i]!=x[k][i]) return temp; } temp=s.substr(0,pos); //string类可以直接运算真的太方便了 temp+=y[k]; temp+=s.substr(pos+x[k].length()); //sbustr(pos)取从pos开始的子串 return temp; } void bfs() { queue<node> q; node s; s.t=a; s.step=0; q.push(s); while(!q.empty()) { node now=q.front(); q.pop(); string temp; if(vis.count(now.t)==1) continue; if(now.t==b) { ans=now.step; break; } vis[now.t]=1; for(int i=0; i<now.t.length(); i++) //逐个字符搜索 for(int j=0; j<n; j++) //逐个转换方式搜索 { temp=convert(now.t,i,j); if(temp!="") { node next; next.t=temp; next.step=now.step+1; q.push(next); } } } if(ans>0 && ans<=10) cout<<ans<<endl; else cout<<"NO ANSWER!"<<endl; } int main() { cin>>a>>b; while(cin>>x[n]>>y[n]) //不知道多少组数据 只剩ctrl+z结束输入 n++; bfs(); return 0; }