网上看到很多形形色色的解决方法,感觉自己挺与众不同的,来分享一下。
以下是原题:
初始状态的步数就算1,哈哈
输入:第一个3*3的矩阵是原始状态,第二个3*3的矩阵是目标状态。
输出:移动所用最少的步数
Input
2 8 3
1 6 4
7 0 5
1 2 3
8 0 4
7 6 5
Output
6
----------------------------------------------------------- 分割线 ---------------------------------------------------------
题目介绍的含糊不清,大致意思是:在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。(和小时候手机上玩的拼图差不多)
解决方法是用宽度优先搜索,宽度优先搜索的万能模板如下(出自算法笔记):
void BFS(int s){
queue q;
q.push(s);
while(!q.empty()){
取出队首元素top;
访问队首元素top;
将队首元素出队;
将top的下一层结点中未曾入队的结点全部入队,并设置为已入队;
}
}
接下来,上代码:
------------------------------------------分割线---------------------------------------------------
解释一下结构体变量的state以及judge函数中的(i-state):
当矩阵空位进行一次移动后,为了防止下一次移动又返回原样,如:
2 8 3 2 8 3 2 8 3
1 6 4 —> 1 0 4 —> 1 6 4
7 0 5 7 6 5 7 0 5
第一次进行上移操作,第二次进行下移操作又使矩阵恢复成原装,如此反复进行造成死循环
所以需要记录位移操作,很多方法都用map,数组等,笔者的方法可能不是很好,如下:
第一次做了上移第二次就不能下移,上下和左右是相排斥的。
四个位置的移动i=0,1,2,3分别代表上、左、下、右,上和下为0,2,左和右为1,3,两者差皆为绝对值2
用state记录当前移动的参数i,在下一次就行移动时,判断绝对值(i-state)是否为2,为2则不合法。
#include
#include
#include
using namespace std;
//定义代表当前矩阵
struct Node{
int a[3][3]; //矩阵的元素储存
int y; //(y,x)为空位0的坐标
int x;
int step; //step为当前移动的步数
int state; //state为当前矩阵的移动状态(具体看如下使用)
}node;
int b[3][3]; //二维数组b为目标矩阵
int t1[4]={-1,0,1,0};
int t2[5]={0,-1,0,1}; //0~4代表上左下右四个位置的移动
//判断当前结点的移动是否合法
bool judge(int y,int x,int i,int state){
if(y>2||y<0||x>2||x<0)
return false;
if(abs(i-state)==2)
return false;
return true;
}
//交换矩阵中0与其相邻位置的数字,视为移动
void exchange(int &a,int &b){
int temp;
temp=a;
a=b;
b=temp;
}
//判断当前矩阵与目标矩阵b是否相等
bool equal(int a[3][3],int b[3][3]){
int i,j;
for(i=0;i<3;i++)
for(j=0;j<3;j++){
if(a[i][j]!=b[i][j])
return false;
}
return true;
}
void BFS(){
queue q;
q.push(node);
while(!q.empty()){ //只要队列不空,就说明还有元素可以移动
node=q.front(); //取出队首元素赋值给node当前矩阵,访问node
q.pop();
if(equal(node.a,b)) //第一次出现当前矩阵与目标矩阵相等的情况,就是最短步数
{
printf("%d\n",node.step);
return;
}
for(int i=0;i<4;i++){ //对当前矩阵的空位0进行上下左右的移动,得到新的空位结点
int newY=node.y+t1[i];
int newX=node.x+t2[i];
if(judge(newY,newX,i,node.state)){ //判断当前移动是否合法
Node t=node;
exchange(t.a[node.y][node.x],t.a[newY][newX]); //进行结点交换(移动)
t.y=newY;
t.x=newX;
t.step=node.step+1; //步数加1
t.state=i; //记录当前移动状态
q.push(t);
}
}
}
}
int main(){
int i,j;
for(i=0;i<3;i++) //输入原始矩阵,储存到node
for(j=0;j<3;j++){
scanf("%d",&node.a[i][j]);
if(node.a[i][j]==0){ //如果输入的是0,则保存空点的状态
node.state=10;
node.y=i;
node.x=j;
node.step=1;
}
}
for(i=0;i<3;i++) //输入目标矩阵
for(j=0;j<3;j++)
scanf("%d",&b[i][j]);
BFS();
return 0;
}