八数码问题
一、问题描述
所谓八数码问题是指:将分别标有数字1,2,3,…,8的八块正方形数码牌任意地放在一块3×3的数码盘上。放牌时要求不能重叠。于是,在3×3的数码盘上出现了一个空格。现在要求按照每次只能将与空格相邻的数码牌与空格交换的原则,将任意摆放的数码盘逐步摆成某种特殊的排列。
二、问题分析
首先,八数码问题包括一个初始状态(strat) 和 目标状态(goal),所谓解八数码问题就是在两个状态间寻找一系列可过渡状态(strat-> strat 1-> strat 2->...->goal)。这个状态是否存在就是我们要解决的第一个问题。如下是初使状态到目标状态图:(0表示空格)
1 | 2 | 3 |
7 | 4 | 5 |
8 | 0 | 6 |
1 | 2 | 3 |
4 | 5 | 6 |
7 | 8 | 0 |
三、数据结构
定义结构体Node如下:
typedef struct{
int num[9];
char cur_expension; //记录是否可以扩展,Y代表可以扩展,N代表不可以
char Operate; //表示不可以执行的操作,L代表不能左移,R代表不能右移,
//U代表不能上移,D代表不能下移,C代表可以任意移动。
int father; //记录父节点的下标。
}Node;
Node state[MAXSIZE];
四、广度优先搜索
广度优先搜索是指按节点的层次进行搜索,本层的节点没有搜索完毕时,不能对下层节点进行处理,即深度越小的节点越先得到扩展,也就是说先产生的节点先得以扩展处理,直至找到目标为止。求解八数码问题的搜索过程:如图2所示,把所有可能的算符应用到开始节点(即空格上移、空格左移、空格右移、空格下移),图2只是演示了两个扩展结点,如此继续下去,直到发现目标节点。
变量定义及函数说明:
#define SUM 100 //限定只搜索前100步,100步以后如果仍然没有搜索到结果,认为无解。
#define MAXSIZE 200 //定义最大数组长度
int n=1; //用来记录搜索的步骤
int goal[9]={1,2,3,7,4,5,8,0,6};//所要达到的最终状态,0代表空格
int same(int temp); //判断是否达到了目标状态
void printgoal(); //输出搜索结果
int left(int temp); //将空格进行左移操作
int right(int temp); //将空格进行右移操作
int up(int temp); //将空格进行上移操作
int down(int temp); //将空格进行下移操作
void init(); //初始状态参数设置
五、 程序运行结果
从初始状态到目标状态走了42步
六、源程序如下
#include <iostream>
#include <stdlib.h>
using namespace std;
int same(int temp); //判断是否达到了目标状态
void printgoal(); //输出搜索结果
int left(int temp); //将空格进行左移操作
int right(int temp); //将空格进行右移操作
int up(int temp); //将空格进行上移操作
int down(int temp); //将空格进行下移操作
void init(); //初始状态参数设置
#define SUM 100 //限定只搜索前100步,100步以后如果仍然没有搜索到结果,认为无解
#define MAXSIZE 200
int n=1;
int goal[9]={1,2,3,7,4,5,8,0,6};//所要达到的最终状态,0代表空格
typedef struct{
int num[9];
char cur_expension; //记录是否可以扩展,Y代表可以扩展,N代表不可以
char Operate; //表示不可以执行的操作,L代表不能左移,R代表不能右移,
//U代表不能上移,D代表不能下移,C代表可以任意移动。
int father; //记录父节点的下标。
}Node;
Node state[MAXSIZE]; //将搜索过的状态存储于该数组中。
int main()
{
init();
if(same(0))
{
cout<<"没有必要进行搜索,初始状态即为最终状态!"<<endl;
while (true);
}
for(int i=0;i<SUM;i++) //开始进行广度搜索,限定搜索上限为100步。
{
if(state[i].cur_expension=='Y')
{
if(state[i].Operate=='L')
{
up(i);
right(i);
down(i);
}
if(state[i].Operate=='R')
{
left(i);
up(i);
down(i);
}
if(state[i].Operate=='U')
{
left(i);
right(i);
down(i);
}
if(state[i].Operate=='D')
{
left(i);
up(i);
right(i);
}
if(state[i].Operate=='C')
{
left(i);
up(i);
right(i);
down(i);
}
}
if(n>=SUM) //100步以后仍然没有达到所要求的状态,认为无解。
{
n--;
printgoal();
cout<<"对不起,在所在搜索范围内没有搜索到结果!"<<endl;
while (true);
}
}
while(1);
return 0;
}
int same(int temp) //判断是否达到了目标状态。
{
for(int j=0;j<9;j++)
if(state[temp].num[j]!=goal[j])
return 0;
return 1;
}
void printgoal() //输出搜索结果。
{
for(int j=1;j<=n;j++)
{
cout<<"第"<<j<<"步搜索后:"<<endl;
cout<<state[j].num[0]<<" "<<state[j].num[1]<<" "<<state[j].num[2]<<endl;
cout<<state[j].num[3]<<" "<<state[j].num[4]<<" "<<state[j].num[5]<<endl;
cout<<state[j].num[6]<<" "<<state[j].num[7]<<" "<<state[j].num[8]<<endl;
cout<<endl;
}
cout<<"成功搜索得到结果!"<<endl;
}
int left(int temp) //将空格进行左移操作。
{
int j;
for(j=0;j<9;j++) //判断空格的位置。
if(state[temp].num[j]==0)
break;
if(j==0||j==3||j==6)
return 0;
for(int k=0;k<9;k++)
state[n].num[k]=state[temp].num[k];
int tempNum=state[n].num[j-1]; //将移动后的状态赋给state[n]
state[n].num[j-1]=0;
state[n].num[j]=tempNum;
state[temp].cur_expension='N';
state[n].Operate='R';
state[n].cur_expension='Y';
state[n].father=temp;
if(same(n)) //判断state[n]是否为最终想得到的状态。
{
printgoal();
while (true);
}
n++;
return 1;
}
int right(int temp) //将空格进行右移操作。
{
int j=0;
for(;j<9;j++)
if(state[temp].num[j]==0)
break;
if(j==2||j==5||j==8)
return 0;
for(int k=0;k<9;k++)
state[n].num[k]=state[temp].num[k];
int tempNum=state[n].num[j+1];
state[n].num[j+1]=0;
state[n].num[j]=tempNum;
state[temp].cur_expension='N';
state[n].Operate='L';
state[n].cur_expension='Y';
state[n].father=temp;
if(same(n))
{
printgoal();
while (true);
}
n++;
return 1;
}
int up(int temp) //将空格进行上移操作。
{
int j=0;
for(;j<9;j++)
if(state[temp].num[j]==0)
break;
if(j==0||j==1||j==2)
return 0;
for(int k=0;k<9;k++)
state[n].num[k]=state[temp].num[k];
int tempNum=state[n].num[j-3];
state[n].num[j-3]=0;
state[n].num[j]=tempNum;
state[temp].cur_expension='N';
state[n].Operate='D';
state[n].cur_expension='Y';
state[n].father=temp;
if(same(n))
{
printgoal();
while (true);
}
n++;
return 1;
}
int down(int temp) //将空格进行下移操作。
{
int j=0;
for(;j<9;j++)
if(state[temp].num[j]==0)
break;
if(j==6||j==7||j==8)
return 0;
for(int k=0;k<9;k++)
state[n].num[k]=state[temp].num[k];
int tempNum=state[n].num[j+3];
state[n].num[j+3]=0;
state[n].num[j]=tempNum;
state[temp].cur_expension='N';
state[n].Operate='U';
state[n].cur_expension='Y';
state[n].father=temp;
if(same(n))
{
printgoal();
while (true);
}
n++;
return 1;
}
void init()
{
Node start;
cout<<"初始状态为:(0代表空格)"<<endl;//初始的状态的生成。
for(int i=0;i<9;i++)
{
start.num[i]=(i+1)%9;
cout<<start.num[i]<<" ";
if((i+1)%3==0)
cout << endl;
}
cout<<endl;
cout<<"目标状态为:"<<endl;
for(int i=0;i<9;i++){
cout<<goal[i]<<" ";
if((i+1)%3==0)
cout << endl;
}
cout<<endl;
for(int k=0;k<9;k++)
if(start.num[k]==0)
break;
start.Operate='C';
start.cur_expension='Y';
start.father=-1;
state[0]=start; //将初始状态赋于state[0]。
}