八数码问题

在一个3*3的棋盘上放置编号为1~8的八个方块,每个方块占一格,另外还有一个空格。与空格相邻的数字方块可以移动到空格上。任务一:指定初始棋盘和目标棋盘,计算出最少的移动步数;任务2:输出数码的移动序列。

​ 把空格看成0,一共9个数字。

​ 输入样例:
​ 1 2 3 0 8 4 7 6 5
​ 1 0 3 8 2 4 7 6 5
​ 输出样例
​ 2
把一个棋局看成一个状态图,总共有9!=362880个状态。从初始棋局开始,每次移动转到下一个状态,到达目标棋局后停止。

​ 下图是样例的转移过程。该图的起点为(A,0),A表示状态,即{1 2 3 0 8 4 7 6 5}这个棋局;0是距离起点的步数。从初始状态A出发,移动数字0到邻居位置,按上下左右的顺序,有3个转移状态B,C,D;目标状态是F,停止。

用队列描述这个BFS过程:

(1)A进队,当前队列是{A};

(2)A出队,A的邻居B,C,D进队,当前队列是{B,C,D},步数为1;

(3)B出队,E进队,当前队列是{C,D,E},E的步数是2;

(4)C出队,转移到F,检验F是目标状态,停止,输出F的步数2。

仔细分析上述过程,发现从B状态出发实际上有E,X两个转移方向,而X正好是初始状态A,重复了。同理Y状态也是重复的。如果不去掉这些重复状态,程序会产生很多无效操作,复杂度大大增加。因此,八树码的重要问题其实是判重。

​ 如果用暴力的方法判重,每次把新状态与9!=362880个状态对比,可能有9!*9!次检查,不可行。因此需要一个快速的判断方法。本文章使用数学方法“康托展开”来判重。
代码实现如下

#include<Bits.h>
#include<queue>
#include<cstdio>
#include<iostream>
using namespace std;
const int LEN = 362880;//状态共9!=362880种
struct node {int state[9];//记录一个八数码的排列,即一个状态int dis;//记录到起点的距离
};int dir[4][2] = { {-1,0},{0,-1},{1,0},{0,1} };//左、右、上、下顺时针方向,左上角的坐标为(0,0)
int visited[LEN];//与每个状态对应的记录,Cantor()函数对它置数,并判重
int start[9];//开始状态
int goal[9];//目标状态
long int factoty[] = { 1,1,2,6,24,120,720,5040,40320,362880 };//康托用到的常数bool Cantor(int str[], int n) {long result = 0;for (int i = 0; i < n; i++) {int counted = 0;for (int j = i + 1; j < n; j++) {if (str[i] > str[j])++counted;}result += counted * factoty[n - i - 1];}if (!visited[result]) {visited[result] = 1;return 1;}elsereturn 0;
}int bfs() {node head;memcpy(head.state, start, sizeof(head.state));//复制起点的状态head.dis = 0;queue<node> q;//队列中的内容是记录状态Cantor(head.state, 9);//用康托展开判重,目的是对起点的visited[]赋初值q.push(head);while (!q.empty()) {head = q.front();if (memcmp(head.state, goal, sizeof(goal)) == 0)//与目标状态对比return head.dis;//到达目标状态,返回距离,结束q.pop();int z;for (z = 0; z < 9; z++)//寻找0的位置if (head.state[z] == 0)break;int x = z % 3;//横坐标int y = z / 3;//纵坐标for (int i = 0; i < 4; i++) {int newx = x + dir[i][0];//元素0转移后的新坐标int newy = y + dir[i][1];int nz = newx + (3 * newy);//转化为一维if (newx >= 0 && newx < 3 && newy >= 0 && newy < 3) {//未越界node newnode;memcpy(&newnode, &head, sizeof(struct node));//复制这个新的状态swap(newnode.state[z], newnode.state[nz]);//把0移动到新的位置newnode.dis++;if (Cantor(newnode.state, 9))//用康托展开判重q.push(newnode);//把新的状态放入队列}}}return -1;//没找到
}int main() {memset(visited, 0, sizeof visited);for (int i = 0; i < 9; i++)cin >> start[i];//初始状态cout << "终态";for (int j = 0; j < 9; j++)cin >> goal[j];//目标状态int num = bfs();if (num != -1)cout << num << endl;else cout << "Impossible" << endl;return 0;
}

更多八数码求解可转八数码八境界

八数码问题BFS算法相关推荐

  1. HUD 1043 Eight 八数码问题 A*算法 1667 The Rotation Game IDA*算法

    先是这周是搜索的题,网站:http://acm.hdu.edu.cn/webcontest/contest_show.php?cid=6041 主要内容是BFS,A*,IDA*,还有一道K短路的,.. ...

  2. c语言八数码A星算法代码解析,八数码问题c语言a星算法详细实验报告含代码解析...

    八数码问题c语言a星算法详细实验报告含代码解析 (13页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 14.9 积分 一.实验内容和要求 八数码问题:在3 ...

  3. python 八数码_python 处理八数码 双向BFS 拼图游戏 | 学步园

    我的代码一开始是单向的BFS 然后很慢,5分钟? 参照别人的代码后,改用双向BFS 很快 拼图问题 == 八数码问题 从开始状态start,进行BFS 同时,从结束状态end,进行BFS 如果左图能够 ...

  4. 八数码 问题 BFS+Cantor

    #include<bits/stdc++.h> using namespace std; const int LEN=362880; //状态总共362880 struct node{in ...

  5. python解决八数码问题_A*算法解决15数码问题_Python实现

    1问题描述 数码问题常被用来演示如何在状态空间中生成动作序列.一个典型的例子是15数码问题,它是由放在一个4×4的16宫格棋盘中的15个数码(1-15)构成,棋盘中的一个单元是空的,它的邻接单元中的数 ...

  6. 八数码问题a*算法c语言,八数码问题的A*算法求解

    A*算法是启发式搜素算法中较为出名和高效的算法之一,其关键是对于启发式函数的实际,启发式函数h(x)需要尽可能的接近实际的 .下面是人工智能八数码问题使用A*算法求解的源码放在博客上记录一下.程序使用 ...

  7. 八皇后问题和八数码问题的最陡上升爬山法、首选爬山法、随机重启爬山法、模拟退火算法的分析和实现

    对经典算法的问题的回顾与感想 对八皇后问题和八数码问题分别用最陡上升爬山法.首选爬山法.随机重启爬山法.模拟退火算法来实现,并且分析他们的性能. 分析 要求实现的各个算法是有共同点的,比如,八皇后问题 ...

  8. 八数码问题及A*算法

    一.八数码问题 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同.棋盘上还有一个空格,与空格相邻的棋子可以移到空格中.要求解决的问题是: ...

  9. 算法提高课-搜索-A*(A star)算法-AcWing 179. 八数码:A星算法求解

    题目分析 来源:acwing 分析: A*算法是什么呢? A算法是一种bfs的变式,需要用到一个"估价函数",用来计算任意状态到目标状态所需代价的估计值.然后在搜索中,维护一个堆, ...

  10. 题目2:隐式图的搜索问题(A*算法解决八数码)

    数据结构课程实践系列 题目1:学生成绩档案管理系统(实验准备) 题目2:隐式图的搜索问题(A*算法解决八数码) 题目3:文本文件单词的检索与计数(实验准备) 文章目录 数据结构课程实践系列 题目1:学 ...

最新文章

  1. mabatisplus怎么给实体类自定义属性_吊打面试官之:当实体类中的属性名和表中的字段名不一样 ,怎么办 ?...
  2. apache php隐藏头信息的方法,apache、php隐藏http头部版本信息的实现方法
  3. 树莓派 php mysql 中文_使用树莓派(raspberry pi)搭建网站(nginx+php+mysql+ddclient)
  4. php 呼叫中心 源码,FreeSWITCH+Workerman+PHP 搭建呼叫中心
  5. git学习(三)版本的前进后退
  6. 单链表的回文判断(O(n)时间复杂度和O(1)的空间复杂度)
  7. linux大文件分割与合并
  8. mac vscode 背景半透明_武装Mac|常用MacBook软件分类汇总
  9. Listary与QTtabbar整合
  10. tomcat启动过程报the JDBC Driver has been forcibly unregistered问题的修复的一种方法
  11. 计算机英特尔显卡在哪找,Win10英特尔显卡设置图标不见了该怎么办?
  12. 笔记本连接android手机屏幕,实现手机、电脑屏幕共享的7个步骤
  13. python高级函数_python高级之函数
  14. 洋流[Theocean flow]介绍----科普知识
  15. java兵临城下_[编程题] 兵临城下
  16. 为opencv添加附加依赖库
  17. 【实战技能】从《Beautiful Teams》一书看团队
  18. 利用kali爆破telnet
  19. linux mint安装金山快盘
  20. mysql查询出过去一个月_mysql查询过去一月半年一年的时间

热门文章

  1. 信息收集--wmic命令
  2. 音乐服务器 linux,Linux 下五个很酷的音乐播放器
  3. Window环境MatConvNet安装
  4. java判断接口地址是否存在_java.util.Iterator接口中的hashNext()方法是用来判断集合中是否存在下一个元素的()_学小易找答案...
  5. git 码云上传本地项目
  6. 常犇_武汉大学管理学院2019年工商管理硕士(MBA)第三批复试通知
  7. c语言precede函数怎么构造,数据结构——栈的应用(表达式求值)(C语言)
  8. Proteus 8.6 SP2 Pro 汉化破解版(附破解文件+汉化包+安装教程) 兼容win10
  9. matlab图像的读取和存储,二、Matlab图像的读取和存储
  10. 终端神器MobaXterm及专业破解版下载