搜索:最小步数模型

模板:这些的题型的大部分模板无非是在一个点有多个选择,直到找到最终答案,而困难一些的选项可能就是加一个路径

(题目截图均来自于Acwing)

经典例题:

魔板:

 思路:这道题发现每一种变换形式都有3种变换选项,所以呢,这里可以通过将字符数组转换成字符串的形式改变排列方式,随后通过到达这一个排列方式的步数来判段这个方式是否走过,如果没走过加入队列中,且将这个点的前置点设为当前排列方式,并且需要记录怎么走的

这里代码有点长,但是3个操作无非是题中所给,都比较简单,set和get方法是字符串和字符数组相互转换的方式

实现代码

#include<bits/stdc++.h>
using namespace std;
char g[2][4];
unordered_map<string,pair<char,string>> pre;//到这一步的前置是经过了哪步,且通过什么操作
unordered_map<string,int> dist;//到这一步经过了几次变换
void SET(string state){
    for(int i=0;i<4;i++) g[0][i]=state[i];
    for(int i=7,j=0;j<4;i--,j++) g[1][j]=state[i];//这里注意要逆时针取出
}
string get(){
    string res;
    for(int i=0;i<4;i++) res+=g[0][i];
    for(int i=3;i>=0;i--) res+=g[1][i];
    return res;
}
//3中move均为题中所给操作,如题意直接写
string move0(string state){
    SET(state);
    for(int i=0;i<4;i++) swap(g[0][i],g[1][i]);
    return get();
}
string move1(string state){
    SET(state);
    int v0=g[0][3],v1=g[1][3];
    for(int i=3;i>=0;i--){
        g[0][i]=g[0][i-1];
        g[1][i]=g[1][i-1];
    }
    g[0][0]=v0;
    g[1][0]=v1;
    return get();
}

string move2(string state){
    SET(state);
    int v=g[0][1];
    g[0][1] = g[1][1];
    g[1][1] = g[1][2];
    g[1][2] = g[0][2];
    g[0][2] = v;
    return get();
}
int bfs(string start,string end){
    if(start==end) return 0;
    queue<string> q;
    q.push(start);
    dist[start]=0;
    while(q.size()){
        auto t=q.front();
        q.pop();
        string m[3];
        m[0]=move0(t);
        m[1]=move1(t);
        m[2]=move2(t);
        for(int i=0;i<3;i++){
            if(!dist.count(m[i])){
                //如果当前没有走过这个排列方式
                dist[m[i]]=dist[t]+1;
                pre[m[i]]={'A'+i,t};//记录当前通过何种操作方式,且前一个排列是哪项
                q.push(m[i]);
                if(m[i]==end) return dist[end];
            }
        }
    }
    return -1;
}
int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int x;
    string start,end;
    for(int i=0;i<8;i++){
        cin>>x;
        end+=char(x+'0');
    }//从后往前才可以记录pre
    for(int i=1;i<=8;i++) start+=char(i+'0');
    int step=bfs(start,end);
    cout<<step<<endl;
    string res;
    while(end!=start){
        res+=pre[end].first;//记录前置点是哪个,怎么走的
        end=pre[end].second;//走到他记录的前置点
    }
    reverse(res.begin(),res.end());//因为是从后往前的,所以翻转一下
    if(step>0) cout<<res;
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值