字串变换-------------------------双向广搜(BFS优化+针对最小步数模型)

已知有两个字串 A, B 及一组字串变换的规则(至多6个规则):

A1 -> B1
A2 -> B2

规则的含义为:在 A 中的子串 A1 可以变换为 B1、A2 可以变换为 B2 …。

例如:A=’abcd’ B=’xyz’

变换规则为:

‘abc’->‘xu’ ‘ud’->‘y’ ‘y’->‘yz’

则此时,A 可以经过一系列的变换变为 B,其变换的过程为:

‘abcd’->‘xud’->‘xy’->‘xyz’

共进行了三次变换,使得 A 变换为B。

输入格式
输入格式如下:

A B
A1 B1
A2 B2 |-> 变换规则
… … /

所有字符串长度的上限为 20。

输出格式
若在 10 步(包含 10步)以内能将 A 变换为 B ,则输出最少的变换步数;否则输出”NO ANSWER!”

输入样例:
abcd xyz
abc xu
ud y
y yz
输出样例:
3

解析:
双向广搜一般应用于最小步数模型
每次选择队列中数量较小的一部分,以达到平衡

#include<bits/stdc++.h>
using namespace std;
const int N=1e5;
int n;
int step;
string a[N],b[N];
int extend(queue<string> &q,unordered_map<string,int> &da,unordered_map<string,int> &db,string a[],string b[])
{
    auto t=q.front();
    q.pop();
    for(int i=0;i<t.size();i++)//枚举t串的每个部分,看是否能被替换
    {
        for(int j=0;j<n;j++)//枚举替换的部分
        {
            if(t.substr(i,a[j].size())!=a[j]) continue;
            string r=t.substr(0,i)+b[j]+t.substr(a[j].size()+i);//找到了可以替换的地方,那么我们需要截取t串下标为0,长度i+替换的部分+后面剩余的部分
            if(db.count(r)!=0) return db[r]+1+da[t];//如果r这个状态存在的话db中,那么我们就需要返回db[r]+1+da[t](解释:db[r]搜到r的步数。da[t]+1:t这个状态转换为r这个状态所以需要+1)
            if(da.count(r)) continue;//如果r状态再da出现过就不需要了
            da[r]=da[t]+1;//距离+1
            q.push(r);//入队
        }
    }
    return -1;
}
int bfs(string A,string B)
{
    unordered_map<string,int> da,db; //设置双向
    queue<string> qa,qb; //初始化
    qa.push(A);
    da[A]=0;
    qb.push(B);
    db[B]=0;
    while(qa.size()&&qb.size())
    {
        int t;
        if(da[qa.front()]+db[qb.front()]>10) return 11;//如果两个方向所搜到的状态,都无法在图上连通,且两个方向上的步数和大于10,则不满足。
        if(qa.size()<=qb.size()) t=extend(qa,da,db,a,b);//因为是双向,每次去队列数量较小的一面,以致达到平衡
        else t=extend(qb,db,da,b,a);
        if(t!=-1) return t;
    }
    return 11;
}
int main()
{
    string A,B;
    cin>>A>>B;
    while(cin>>a[n]>>b[n]) n++;
    step=bfs(A,B);
    if(step>10) puts("NO ANSWER!");
    else printf("%d\n",step);
}
发布了383 篇原创文章 · 获赞 7 · 访问量 8036

猜你喜欢

转载自blog.csdn.net/qq_43690454/article/details/104255035