个人思路与理解(建议小白阅读)
整体思路:
1、从初始状态要想到该状态的话,一共为我们提供了三种操作,A,B,C,那我们想到这个状态的话,我们就这三种操作都会使用
2、但是我们又不知道具体的我们该如何去操作,所以我们就枚举每一种操作的可能,这就是bfs的搜索
3、因为我们有三种操作,所以我们就将三种操作任意组合起来,然后每次都搜索一下就好了
4、也就是说我们通过搜索的方式实现我们本不知道如何组织的操作(也就是我们不知道怎么找最优解,就把所有情况都枚举一遍)
5、然后得到这么一个结果,而我们利用宽度优先搜索的方式第一次搜到的一定是最小的操作次数了
6、然后这个题目特别的让我们要按照字典序最小输出
7、y总说其实这种用字典序最小输出一般来说不会影响原题最开始的算法,只不过是说为了出题者更好的判题进行服务
8、所以我们只需要稍微做一些考虑就好了,不用想的那么复杂,原本的算法是不会被改变的
9、所以总结起来就是,这种题目,由于确实无法准确的知道最优解,那么我们就枚举所有的方式,知道找到最优解
10、特别的,这题目的状态需要特殊处理的表示,也算是这种题目的特色以及难点吧,也是需要我们这些新手来特殊学习的!
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<unordered_map>
#include<queue>
#define l first
#define r second
using namespace std;
const int N=5;
char a[N][N];//这只是一个中间过渡的变量
//第一个参数代表我们当前是哪一个字符串,后面第一个参数代表我们当前是从哪一步(A/B/C)过来的,以及我们是从哪个字符串过来的
unordered_map<string,pair<char,string>>pre;//第一个参数代表的是宿主,后面的是代表数组的一些性质
unordered_map<string,int>dist;
void set(string state)//把我们的字符串先转换为数组,以便我们进行题中描述的操作
{
for(int i=0;i<4;i++)a[1][i]=state[i];//第一行
for(int i=7,j=0;j<4;i--,j++)a[2][j]=state[i];//第二行
//0~3顺序赋值
//4~7逆序赋值
}
string get()//再将操作完的数组换成字符串
{
string s;
for(int i=0;i<=3;i++)s+=a[1][i];
for(int i=3;i>=0;i--)s+=a[2][i];
//第一行顺着给它,第二行,逆着给它
return s;
}
string change1(string state)//第一种改变策略
{
set(state);
for(int i=0;i<4;i++)swap(a[1][i],a[2][i]);
return get();
}
string change2(string state)//第二种改变策略
{
set(state);
int shang=a[1][3];
int xia=a[2][3];
for(int i=3;i>=0;i--)
{
a[1][i]=a[1][i-1];
a[2][i]=a[2][i-1];
}
a[1][0]=shang;
a[2][0]=xia;
return get();
}
string change3(string state)//第三种改变策略
{
set(state);
int s=a[1][1];
a[1][1]=a[2][1];
a[2][1]=a[2][2];
a[2][2]=a[1][2];
a[1][2]=s;
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 state3[4];
state3[1]=change1(t);
state3[2]=change2(t);
state3[3]=change3(t);
for(int i=1;i<=3;i++)
if(!dist[state3[i]])//如果我们这个位置没有遍历过的话,那就遍历一下
{
dist[state3[i]]=dist[t]+1;
pre[state3[i]]={'A'+(i-1),t};
q.push(state3[i]);
if(state3[i]==end)return dist[end];//如果已经找到了终点,那就直接return
}
}
return -1;//数据保证有解的,这里要不要都一样,但是为了严谨,还是随便return一个
}
int main()
{
string start,end;
for(int i=1;i<=8;i++)start+=char(i+'0');//初始化一下基本状态
for(int i=1;i<=8;i++)
{
int x;
scanf("%d",&x);
end+=char(x+'0');//初始化一下特殊状态
}
int ans=bfs(start,end);
printf("%d\n",ans);
string res;
while(end!=start)//找出对应的来源
{
res+=pre[end].l;
end=pre[end].r;
}
reverse(res.begin(),res.end());
if(ans>0)//题目要求
cout<<res<<"\n";
return 0;
}
谢谢分享