题目描述
已知有两个字串 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
---------------------------------------------------------------------------------------------------------------------------------------
和单词接龙有点像,都是字符串,不过这是最少次数,BFS
很多人说要双向广搜,但我随便写写也过了
用个map判重,变换时枚举规则和从哪个位置开始
#include<iostream> #include<cstdio> #include<string> #include<queue> #include<map> using namespace std; string st,ed,x[10],y[10]; int cnt=0; map<string,int> step; queue<string> q; inline bool eq(string &s,int be,int j){ string &tmp=x[j]; int l=min(s.size(),be+tmp.size()); for(int i=be;i<l;i++) if(s[i]!=tmp[i-be]) return false; return true; } string change(string s,int be,int j){ string nw; for(int i=be;i<(int)s.size()-(int)x[j].size()+1;i++) if(eq(s,i,j)){ nw=s.substr(0,i)+y[j]; if(i+x[j].size()<s.size()) nw+=s.substr(i+x[j].size(),s.size()-(i+x[j].size())); return nw; } return ""; } int bfs(){ q.push(st); step[st]=0; while(!q.empty()){ string now=q.front(); q.pop();//cout<<now<<" "<<step[now]<<" now "; int d=step[now]; for(int i=0;i<now.size();i++) for(int j=1;j<=cnt;j++){ string nw=change(now,i,j);//cout<<nw<<" nw "; if(nw=="") continue; if(step.count(nw)) continue; if((step[nw]=d+1)>10) continue;//cout<<nw<<" "<<j<<" nw "; q.push(nw);//if(nw=="xyz") cout<<step[nw]<<" hi "; if(nw==ed) return d+1; } } return false; } int main(){ cin>>st>>ed; cnt=1; while(cin>>x[cnt]>>y[cnt]) cnt++; cnt--;//cout<<cnt<<"cnt "; int ans=bfs(); if(ans==0) cout<<"NO ANSWER!"; else cout<<ans; }