八数码
分析
本题是求最少交换次数,故先想到bfs,而本题的难点在于状态和步数的存储。以及状态的转移。
如何记录下x和一个数交换后的状态?
如何记录步数?
主要思想
一个巧妙的思想可以解决此类问题,状态可以用string类型来记录,求在3*3矩阵中的横纵坐标无非就是将其在string类型中的位序(假设为k)x=k/3,y=k%3。而查询起来也异常方便 直接用find函数即可找到(string类型作为stl的优势),而它的交换次数可用哈希来存储 即可定义unordered<string,int>类型,这样就将其状态和步数都存储了下来。
示例代码
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<queue>
using namespace std;
queue<string>q;
unordered_map<string,int> d; //哈希表存储交换次数
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
string start;
void read()
{
char c;
while(cin>>c)
start+=c;
}
int bfs()
{
string end="12345678x";
q.push(start);
if(start==end) return 0; //如果最开始就为目标位序则直接返回
while(q.size())
{
auto t=q.front();
q.pop();
if(t==end) return d[t];
int dis=d[t];
int k=t.find('x');
int x=k/3,y=k%3; //寻找x在矩阵中的位序
for(int i=0;i<4;i++)
{
int a=x+dx[i];
int b=y+dy[i];
if(a>=0 && a<3 && b>= 0 && b<3 )
{
swap(t[k],t[a*3+b]); //交换,最后需要交换回来以用来进行下一次交换
if(!d.count(t)) //判断是否已经走过
{
q.push(t);
d[t]=dis+1;
}
swap(t[k],t[a*3+b]);
}
}
}
return -1; //如果最后未发现则返回-1
}
int main()
{
read();
cout<<bfs()<<endl;
return 0;
}