有时候从一个点能扩展出来的情况很多,这样几层之后搜索空间就很大了,我们采用从两端同时进行搜索的策略,压缩搜索空间。
190. 字串变换(190. 字串变换 - AcWing题库)
思路:这题因为变化规则很多,所以我们一层一层往外扩展的时候,扩展几层后空间就会变得很大 ,那么就需要换一个思路,我们这里采用双向广搜,从两个方向来进行搜索,具体执行的时候,肯定得先从一个方向开始,那么从哪里开始呢?显然要从状态少的方向开始,我们就比较两个队列,从小的那个队列开始,然后又有新问题了,如果从一个方向开始,什么时候判停去找下一个方向,显然我们可以只往外扩展一层,扩展结束,或者两者头尾交汇的时候停止。
现在理一下我们需要哪些数据结构,首先得有两个队列分别记录从头搜索和从尾搜索的队列,另外要有两个数据结构来记录每个状态从头和从尾更新到它们时的距离。另外还要记录一下变换规则。
还有就是我们每次只往外扩展一层,所以有交汇和不交汇两种情况,如果交汇的话,那么我们可以直接返回从头到这个点和从尾到这个点的步数和,如果这个值小于10,那么显然就是最小距离,因为我们每次只从头或者从尾往外扩展一层,下次扩展时找到的,一定比当前扩展找到的多一步。当然也可能不交汇,因为我们只往外扩展一层,不交汇的时候返回一个大于10的数即可。同时我们每一次往外扩展都要记录步数,当步数大于10的时候直接停下。因为题目要求的上限就是10步。
对了如果想把两个扩展函数写在一起,一定要传入它们的更新规则,两者的扩展规则是不一样的。
#include<bits/stdc++.h>
using namespace std;
string a[10],b[10];
int n;
int expend(queue<string>&q,unordered_map<string,int>&dl,unordered_map<string,int>&dr,string a[],string b[])
{
int d=dl[q.front()];
while(q.size()&&dl[q.front()]==d)
{
auto t=q.front();
//cout<<t<<endl;
q.pop();
for(int i=0;i<n;i++)
{
for(int j=0;j<t.size();j++)
{
if(t.substr(j,a[i].size())==a[i])
{
string tmp=t.substr(0,j)+b[i]+t.substr(j+a[i].size());
if(dr.count(tmp)) return dl[t]+dr[tmp]+1;
if(dl.count(tmp)) continue;
q.push(tmp);
dl[tmp]=dl[t]+1;
}
}
}
}
return 11;
}
int bfs(string s,string e)
{
if(s==e) return 0;
queue<string>ql,qr;
unordered_map<string