【NOIP 2002】【广搜】 字符变换
题目描述:
已知有两个字串A,B及一组字串变换的规则(至多6个规则):
A1 -> B1
A2 -> B2规则的含义为:在 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次变换,使得A变换为B。
输入格式:
输入格式如下:
A B
A 1 B1
A 2 B 2
|-> 变换规则… … /
所有字符串长度的上限为20。
输出格式
输出至屏幕。格式如下:
若在10步(包含10步)以内能将A变换为B,则输出最少的变换步数;否则输出"NO ANSWER!"
输入输出样例
输入 #1 复制
abcd xyz
abc xu
ud y
y yz输出 #1 复制
3
解法:
1 对于串s,查找可以转换的字串,然后把转换后的 新串 压入队列,再次搜索,有再转换压入。。记录一下步数d。
找完后 把串s出掉。
2 继续重复到队列为空。
。。。。这样写最后过不了几个点,必须减枝
需要一个map记录某个串是不是被搜到过,如果已经搜过了就不再继续搜 。
撒旦阿瑟东
比如 这样队列里有两个重复,用map 记录每个新串,如果是访问过的直接出队看下一个。。
代码:
#include<iostream>
#include<queue>
#include<map>
using namespace std;
string a,b;
string sa[8],sb[8];
int n=1;
queue<string> q;
queue<int> d;
map <string,int> mp;
int main(){
cin>>a>>b;
while(cin>>sa[n]>>sb[n]){
n++;
}
n--;
//cout<<n<<endl;
q.push(a);
d.push(0);
while(!q.empty()){
if(q.front() == b){
cout<<d.front()<<endl;
return 0;
}
if(d.front() >= 10){
q.pop();
d.pop();
// cout<<"NO ANSWER!";
// return 0;
}
string t = q.front();
//减枝
if(mp.count(t)){
q.pop();
d.pop();
continue;
}
mp[t]=1;
// cout<<d.front()<<" "<<t<<endl;
for(int i=1;i<=n;i++){
int p=0;
while(t.find(sa[i],p)!=-1){
p = t.find(sa[i],p);
// substr(起点,终点) 到终点可不写,默认.
// substr(0,p) 前面不用换的部分
// sb[i] 中间sa[i]换成sb[i]
//substr(p+sa[i].lensth()) a[i]后面不用换的部分到结尾:
q.push(t.substr(0,p)+sb[i]+ t.substr(p+sa[i].length()));
//q.push( t.replace(p,sa[i].size(),sb[i]) );
d.push(d.front()+1);
p++;
}
}
q.pop();
d.pop();
}
cout<<"NO ANSWER!";
return 0;
}