双向BFS:字串变换

该博客讨论了一种使用双向广度优先搜索(BFS)解决字符串变换问题的方法。在不超过6个规则的情况下,通过双向BFS寻找两个字符串之间的最小变换步数。算法首先从起点A和终点B开始搜索,确保每次扩展队列的一整层,以避免错过可能的更短路径。在搜索过程中,利用unordered_map存储已访问的字符串及其步数。当搜索达到一定步数或找到答案时,返回步数。若无法找到变换路径,则输出'NOANSWER!'。
摘要由CSDN通过智能技术生成

原题链接:https://www.acwing.com/problem/content/192/
在这里插入图片描述
虽然至多只有6个规则,但是可能有很多种变换.
比如abcabcabc, 你可以选择边第一个abc,也可以选择变第二个…

在这里插入图片描述
我们可以让起点A和终点B 进行双向奔赴. 假设各走五步.
在这里插入图片描述
搜索量大大减小.

双向BFS搜的时候, 无论是A还是B,每次都要把一层扩展出来,不能每次只扩展一个点,否则结果有可能是错的.

如果每次只扩展一个点,有可能存在以下情况,他们在某个点相遇了:然后搜索结束,然后我们就认为这是最短距离. 但是

在这里插入图片描述
有可能从距离相同的这一层, 到达下边还有另一个更短的路径. 但是我们没有搜到.
在这里插入图片描述

搜索的时候, 宽度和深度比较大的时候,一般可以考虑双向.

#include<iostream>
#include<cstring>
#include<algorithm>
#include<unordered_map>//比map稍微快一点
#include<queue>

using namespace std;

const int N=6;

int n;
string a[N], b[N];//每次操作的对象都是字符串

string A, B;

// 对q队列进行扩展,  a->b
int extend(queue<string>& q, unordered_map<string, int>&da, unordered_map<string, int>& db, 
    string a[N], string b[N])
{   
    int d = da[q.front()];
    // 在队列前部并且 dist等于队首元素的 
    // 他们都是在同一层的,都需要扩展
    while (q.size() && da[q.front()] == d)
    {
        auto t = q.front();
        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 r = t.substr(0, j) + b[i] + t.substr(j + a[i].size());
                    // 如果db中有了, 就是找到答案了
                    if (db.count(r)) return da[t] + db[r] + 1;
                    // da中有了, 跳过, 开启下一轮.
                    if (da.count(r)) continue;
                    da[r] = da[t] + 1;
                    q.push(r);
                }
    }
    
    // 搜不到返回正无穷
    return 11;
}
int bfs()
{
    if (A == B) return 0;
    // 分别存A 和 B 搜索状态的队列
    queue<string> qa, qb;
    // 分别对A和B, 判断搜到这个状态走了多少步数
    unordered_map<string, int> da, db;

    qa.push(A), qb.push(B);
    da[A] = db[B] = 0;

    int step = 0;
    // 都不空才搜
    // 因为如果其中一个队列空了,说明已经变不成该队列中没出现过的字符串了。
    // 这时如果两个队列仍没出现交集,另一个队列继续搜完全没有意义。
    while (qa.size() && qb.size())
    {
        int t;
        if (qa.size() < qb.size()) t = extend(qa, da, db, a, b);
        else t = extend(qb, db, da, b, a);

        if (t <= 10) return t;
        if ( ++ step == 10) return -1;
    }

    return -1;
}

int main()
{
    cin >> A >> B;
    while (cin >> a[n] >> b[n]) n ++ ;

    int t = bfs();
    if (t == -1) puts("NO ANSWER!");
    else cout << t << endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值