Problem C: 【宽搜入门】8数码难题
[Creator : Imported]
Time Limit : 20.000 sec Memory Limit : 128 MB
Description
初始状态的步数就算1,哈哈
输入:第一个33的矩阵是原始状态,第二个33的矩阵是目标状态。
输出:移动所用最少的步数
Input
2 8 3
1 6 4
7 0 5
1 2 3
8 0 4
7 6 5
Output
6
思路分析:
1.首先这个问题是宽搜的典型题目,当然也可以用多种方法做,例如这位大佬的解题七种方法解决八数字吗问题
2.这里因为我刚入门搜索,所以就用了一般的宽搜,思路是这样的:
首先用两个二维数组存储待处理的矩阵和目标矩阵,用0当作空的模块,其他在0模块的上下左右的数字都可以与之交换,模拟现实中拼图的过程,
3.然后就是普通的宽搜过程,数字0作为搜索的根节点入队,记录步数为1,当前的矩阵为待处理的矩阵,如果队列不为空就一直进入循环,进入循环后读取队首结构体变量top,然后队首出队,用两个一味数组存储上下左右的移动,
4.循环四次搜索队首元素的上下左右是否有符合条件的位置(符合条件就是该位置不越界,而且不能走上一层的上一层位置否则就走回去了)
5.将符合条件的位置信息,放在新的结构体变量的x,y 变量中,步数加 1 ,新定义一个矩阵用于模拟位置交换的操作:新位置(new_x , new_y)和结点的top.x,top.y,在矩阵中的元素交换位置(可以用 algorithm头文件下的swap(num1,num2)函数),然后把交换后的矩阵放入结构体中的当前矩阵变量(可以用 sting.h 头文件下的:memcpy(num1,num2,sizeof(num2))函数实现矩阵的赋值),子节点结构体入队
6.当前队首结点的当前矩阵和目标矩阵相同的时候结束搜索,输出结构体的步数变量,就是最少步数。
搜索的过程如下:
现在思路清楚了,就是去写代码了
#include <iostream>
#include <math.h>
#include <string.h>
#include <queue>
using namespace std;
const int maxn=4;
int d_x[4]={1,0,-1,0};
int d_y[4]={0,-1,0,1};
struct Node{
int x,y,step;
int current[maxn][maxn];
int last[2];
}now,start,aim;
bool same(Node top)
{
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
if(top.current[i][j]!=aim.current[i][j]) return false;
}
}
return true;
}
bool iswill(int x ,int y )
{
if(x<0 || y<0 || x>=3|| y>=3) return false;
return true;
}
void bfs()
{
start.step=1;
queue<Node> q;
q.push(start);
while(!q.empty()){
Node top=q.front();
q.pop();
if(same(top))
{
printf("%d\n",top.step);
return ;
}
for(int i=0;i<4;i++)
{
int new_x=top.x+d_x[i];
int new_y=top.y+d_y[i];
if(iswill(new_x,new_y)&&(new_x!=top.last[0] || new_y!=top.last[1]))
{
now.x=new_x,now.y=new_y;
now.step=top.step+1;
now.last[0]=top.x,now.last[1]=top.y;
int temp[4][4];
memcpy(temp,top.current,sizeof(top.current));
int t=temp[top.x][top.y];
temp[top.x][top.y]=temp[new_x][new_y];
temp[new_x][new_y]=t;
memcpy(now.current,temp,sizeof(temp));
q.push(now);
}
}
}
}
int main()
{
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
scanf("%d",&start.current[i][j]);
//cin>>start.current[i][j];
if(start.current[i][j]==0)
{
start.x=i,start.y=j;
}
}
}
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
scanf("%d",&aim.current[i][j]);
}
}
bfs();
return 0;
}
//y1 是c++ 源码中的一个double 类型的变量,所以一般变量命名的时候不要用y1
小结:
一开始提交的时候一直显示编译错误,但是在编译器上却没有显示有编译的问题,百度后了解到:y1 是c++ 源码中的一个double 类型的变量,所以一般变量命名的时候不要用y1 ,编译错误的原因就是使用了 变量y1,改后ac