AcWing 190. 字串变换 (双向bfs)

 这题使用双向bfs.首先已经知道初始的字符串和终点字符串,我们不妨以初始字符串和终点字符串分别为起点进行bfs,当两个互相搜索到的时候判断两个字符串状态的"距离"(操作次数)是否小于等于10次.

代码如下:

#include <bits/stdc++.h>
// #define LOCAL
#define INF 0x3f3f3f3f3f3f3f3f
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define int long long
#define debug(a) cout << #a << "=" << a << endl;
using namespace std;
const int N = 8;
string bg, ed;
unordered_map<string, int> dbg, ded;
queue<string> qbg, qed;
bool ok;
string a[N], b[N];
int cnt;
int bfs(queue<string> &q, unordered_map<string, int> &da, unordered_map<string, int> &db, string aa[], string bb[]){
    int sz = q.size();
    for (int i = 0; i < sz; ++i){
        string now = q.front();
        q.pop();
        for (int i = 0; i < cnt; i++){
            for (int j = 0; j < now.size(); j++)
                if (now.substr(j, aa[i].size()) == aa[i]){
                    string r = now.substr(0, j) + bb[i] + now.substr(j + aa[i].size());
                    if (db.count(r))
                        return da[now] + db[r] + 1;
                    if (da.count(r))
                        continue;
                    da[r] = da[now] + 1;
                    q.push(r);
                }
        }
    }
    return 11;
}
signed main()
{
#ifdef LOCAL
    freopen("input.in", "r", stdin);
    freopen("output.out", "w", stdout);
#endif
    IOS;
    cin >> bg >> ed;
    dbg[bg] = ded[ed] = 0;
    qbg.emplace(bg);
    qed.emplace(ed);
    string ta, tb;
    while (cin >> ta >> tb)
    {
        a[cnt] = ta, b[cnt] = tb;
        ++cnt;
    }

    if (bg == ed)
    {
        cout << 0 << '\n';
        return 0;
    }
    bool has_ans = false;
    int step = 0;
    int t;
    while (qbg.size() && qed.size())
    {
        if (qbg.size() < qed.size())
            t = bfs(qbg, dbg, ded, a, b);
        else
            t = bfs(qed, ded, dbg, b, a);
        if (t <= 10){
            has_ans = true;
            break;
        }
        if (++step == 10)
            break;
    }
    if (has_ans)
        cout << t << "\n";
    else cout << "NO ANSWER!\n";
}

通过这道题,我总结出几个双向bfs的要注意的点:

1.进行双向bfs时,每一步的拓展其实是拓展一层的节点,我们假设用队列进行bfs,当前一轮拓展初始时队列的大小为size,那么我们就要拓展size次才能把一层的节点全部拓展更新.至于我们为什么要拓展更新一层的节点,这是因为要维持队列的分层性和单调性.

2.计算步数时,不能直接用拓展的次数表示步数(不是不能,而是这样做实在不方便),而是用d数组维护步数,每次更新时更新d数组

3.双向bfs一定要考虑反向的问题,从终点出发的路径和起点的路径是互为镜像的

4.不用同时开d数组和vis数组维护每个点的访问情况,巧用count函数即可.

还有一点就是,substr()函数是真的方便.

substr(pos, length)表示从pos位置起长度为length的子串

substr(pos)表示从pos位置起到字符串结尾的子串

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值