写在前面
这题挺有意思的,让我无从下手······
看别人的题解都得看半天,看到有位大佬写了迭代深搜,我表示不会,还是老老实实的用bfs(广搜)来解决这道题吧
题目链接
思路
题目要求最短步数,显然我们优先考虑bfs
我们可以开2个队列:
一个队列用于存放字符串,一个队列用于存放步数
由于字符串可能会出现重复,我们必须得剪枝,若当前字符串出现过,则将它标记为1,标记用哈希map最为合适
出现过的字符串直接将两个队列的队首出队,然后continue,进行下一次循环
我们枚举当前队列中队头那个串的每一个位置,对每一个位置枚举所有可能的转换手段,然后去尝试拼接
(这里推荐用string中replace函数,可以直接取代字符串中某一位置的子字符串)
匹配成功,则将截取后的字符串放入队列,然后在将步数的队首+1,存入步数队列(一个字符串可能有多个匹配的子串,因此不能只匹配一次,需要匹配多次)
最后判断步数队列的队首是否超过10即可
code
string a[8],b[8];
queue<string> q;
queue<int> step;
int k=1;
string x,y;
unordered_map<string,int> m;
int bfs(){
string s,ss;
while(!q.empty() && q.front()!=y && step.front()<=10){//队列不为空且可以进行操作
if(m[q.front()]){//去重
q.pop();
step.pop();
continue;
}
m[q.front()]=1;
for(int i=1;i<=k;++i){
s=q.front();
while(1){//一个字符串需要多次匹配
int t=s.find(a[i]);
if(t==-1) break;
ss=q.front();
ss.replace(t,a[i].size(),b[i]);//替换字符串
q.push(ss);
step.push(step.front()+1);//步数+1
s[t]=' ';//防止当前位置再次被匹配
}
}
q.pop();
step.pop();
}
if(q.empty()||step.front()>10) return -1;
return step.front();
}
void solve(){
cin >> x >> y;
while(cin >>a[k] >>b[k]){
k++;
}
k--;
q.push(x);
step.push(0);//首先存入0,防止队列为空
int ans=bfs();
if(ans==-1){
cout << "NO ANSWER!";
}
else cout << ans;
return ;
}