八数码问题BFS算法
八数码问题
在一个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算法相关推荐
- HUD 1043 Eight 八数码问题 A*算法 1667 The Rotation Game IDA*算法
先是这周是搜索的题,网站:http://acm.hdu.edu.cn/webcontest/contest_show.php?cid=6041 主要内容是BFS,A*,IDA*,还有一道K短路的,.. ...
- c语言八数码A星算法代码解析,八数码问题c语言a星算法详细实验报告含代码解析...
八数码问题c语言a星算法详细实验报告含代码解析 (13页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 14.9 积分 一.实验内容和要求 八数码问题:在3 ...
- python 八数码_python 处理八数码 双向BFS 拼图游戏 | 学步园
我的代码一开始是单向的BFS 然后很慢,5分钟? 参照别人的代码后,改用双向BFS 很快 拼图问题 == 八数码问题 从开始状态start,进行BFS 同时,从结束状态end,进行BFS 如果左图能够 ...
- 八数码 问题 BFS+Cantor
#include<bits/stdc++.h> using namespace std; const int LEN=362880; //状态总共362880 struct node{in ...
- python解决八数码问题_A*算法解决15数码问题_Python实现
1问题描述 数码问题常被用来演示如何在状态空间中生成动作序列.一个典型的例子是15数码问题,它是由放在一个4×4的16宫格棋盘中的15个数码(1-15)构成,棋盘中的一个单元是空的,它的邻接单元中的数 ...
- 八数码问题a*算法c语言,八数码问题的A*算法求解
A*算法是启发式搜素算法中较为出名和高效的算法之一,其关键是对于启发式函数的实际,启发式函数h(x)需要尽可能的接近实际的 .下面是人工智能八数码问题使用A*算法求解的源码放在博客上记录一下.程序使用 ...
- 八皇后问题和八数码问题的最陡上升爬山法、首选爬山法、随机重启爬山法、模拟退火算法的分析和实现
对经典算法的问题的回顾与感想 对八皇后问题和八数码问题分别用最陡上升爬山法.首选爬山法.随机重启爬山法.模拟退火算法来实现,并且分析他们的性能. 分析 要求实现的各个算法是有共同点的,比如,八皇后问题 ...
- 八数码问题及A*算法
一.八数码问题 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同.棋盘上还有一个空格,与空格相邻的棋子可以移到空格中.要求解决的问题是: ...
- 算法提高课-搜索-A*(A star)算法-AcWing 179. 八数码:A星算法求解
题目分析 来源:acwing 分析: A*算法是什么呢? A算法是一种bfs的变式,需要用到一个"估价函数",用来计算任意状态到目标状态所需代价的估计值.然后在搜索中,维护一个堆, ...
- 题目2:隐式图的搜索问题(A*算法解决八数码)
数据结构课程实践系列 题目1:学生成绩档案管理系统(实验准备) 题目2:隐式图的搜索问题(A*算法解决八数码) 题目3:文本文件单词的检索与计数(实验准备) 文章目录 数据结构课程实践系列 题目1:学 ...
最新文章
- mabatisplus怎么给实体类自定义属性_吊打面试官之:当实体类中的属性名和表中的字段名不一样 ,怎么办 ?...
- apache php隐藏头信息的方法,apache、php隐藏http头部版本信息的实现方法
- 树莓派 php mysql 中文_使用树莓派(raspberry pi)搭建网站(nginx+php+mysql+ddclient)
- php 呼叫中心 源码,FreeSWITCH+Workerman+PHP 搭建呼叫中心
- git学习(三)版本的前进后退
- 单链表的回文判断(O(n)时间复杂度和O(1)的空间复杂度)
- linux大文件分割与合并
- mac vscode 背景半透明_武装Mac|常用MacBook软件分类汇总
- Listary与QTtabbar整合
- tomcat启动过程报the JDBC Driver has been forcibly unregistered问题的修复的一种方法
- 计算机英特尔显卡在哪找,Win10英特尔显卡设置图标不见了该怎么办?
- 笔记本连接android手机屏幕,实现手机、电脑屏幕共享的7个步骤
- python高级函数_python高级之函数
- 洋流[Theocean flow]介绍----科普知识
- java兵临城下_[编程题] 兵临城下
- 为opencv添加附加依赖库
- 【实战技能】从《Beautiful Teams》一书看团队
- 利用kali爆破telnet
- linux mint安装金山快盘
- mysql查询出过去一个月_mysql查询过去一月半年一年的时间
热门文章
- 信息收集--wmic命令
- 音乐服务器 linux,Linux 下五个很酷的音乐播放器
- Window环境MatConvNet安装
- java判断接口地址是否存在_java.util.Iterator接口中的hashNext()方法是用来判断集合中是否存在下一个元素的()_学小易找答案...
- git 码云上传本地项目
- 常犇_武汉大学管理学院2019年工商管理硕士(MBA)第三批复试通知
- c语言precede函数怎么构造,数据结构——栈的应用(表达式求值)(C语言)
- Proteus 8.6 SP2 Pro 汉化破解版(附破解文件+汉化包+安装教程) 兼容win10
- matlab图像的读取和存储,二、Matlab图像的读取和存储
- 终端神器MobaXterm及专业破解版下载