八数码

八数码问题

一、问题描述

所谓八数码问题是指:将分别标有数字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]。

}

时间: 2024-08-08 22:00:59

八数码的相关文章

1225 八数码难题

1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.问题描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765

HDU 1043 Eight八数码解题思路(bfs+hash 打表 IDA* 等)

题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原为初始状态 思路: 参加网站比赛时拿到此题目,因为之前写过八数码问题,心中暗喜,于是写出一套暴力bfs+hash,结果TLE呵呵 思路一:bfs+hash(TLE) 1 #include <cstdio> 2 #include <cstring> 3 #include <queu

洛谷【P1379】八数码难题

P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变. 输入输出格式 输入格式: 输入初试状态,一行九个数字,空格用0表示 输出格式: 只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊

八数码三种用时差距极大的写法

进化史,一种比一种长,一种比一种快.不过第三种似乎还不是最终形态. 第一种,傻逼级迭代加深. 去年十一月写的,那时候刚刚学迭代加深,敲了一个钟头才敲完,codevs上直接过,就没太管,觉得这是个水题.实际上呢,看后文. 1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 using namespace std; 6 int sx,sy,lim,

八数码的八境界 [转载]

八数码的八境界   研究经典问题,空说不好,我们拿出一个实际的题目来演绎.八数码问题在北大在线测评系统中有一个对应的题,题目描述如下: Eight Time Limit: 1000MS    Memory Limit: 65536K  Special Judge Description The 15-puzzle has been aroundfor over 100 years; even if you don't know it by that name, you've seen it. I

【转】八数码问题及A*算法

一.八数码问题八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同.棋盘上还有一个空格,与空格相邻的棋子可以移到空格中.要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤.所谓问题的一个状态就是棋子在棋盘上的一种摆法.棋子移动后,状态就会发生改变.解八数码问题实际上就是找出从初始状态到达目标状态所经过的一系列中间过渡状态.八数码问题一般使用搜索法来解.搜索法有广度优先搜索法.深度优

HDU 3567 Eight II(八数码 II)

p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-size: 10.5000pt } h1 { margin-top: 5.0000pt; margin-bottom: 5.0000pt; text-align: center; font-family: 宋体; color: rgb(26,92,200); font-weight: bold; fo

cdoj 1380 Xiper的奇妙历险(2) [八数码问题 bfs + 预处理]

快要NOIP 2016 了,现在已经停课集训了.计划用10天来复习以前学习过的所有内容.首先就是搜索. 八数码是一道很经典的搜索题,普通的bfs就可求出.为了优化效率,我曾经用过康托展开来优化空间,甚至还用过A*来优化时间.不过这道题懒得写了,就一个普普通通的bfs,再加上一个stl 的map就水过了. 首先题目要求有多达10000组数据,依次搜索肯定是不行的,我试过用A*来写,第2组数据就会T掉,所以我们考虑用一个预处理.从末尾状态搜索所有可行的状态,并用一个map来存储答案.然后就很好写了.

BFS(八数码) POJ 1077 || HDOJ 1043 Eight

题目传送门1 2 题意:从无序到有序移动的方案,即最后成1 2 3 4 5 6 7 8 0 分析:八数码经典问题.POJ是一次,HDOJ是多次.因为康托展开还不会,也写不了什么,HDOJ需要从最后的状态逆向搜索,这样才不会超时.判重康托展开,哈希也可. POJ //#include <bits/stdc++.h> #include<iostream> #include<algorithm> #include<string> #include<stack

洛谷OJ P1379 八数码难题 解题报告

洛谷OJ P1379 八数码难题 解题报告 by MedalPluS 题目描述   在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变.   输入格式   输入初试状态,一行九个数字,空格用0表示   输出格式 只有一行,该行只有一个数字,表示从初始状态到