8数码问题 (广度优先算法解决----c++)

8数码问题问题描述

八数码问题也称为九宫问题,在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格(空格用0来表示),空格周围的棋子可以移到空格中。

要求解的问题是:
给出一种初始布局(初始状态)和目标布局(目标状态),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

问题分析

八数码问题的核心在于移动棋子使其得到需要的状态分布(即目标状态),为便于控制操作,我们将每次移动棋子的过程都视为标号为0的棋子与其相邻棋子的位置交换操作。(如下图,2移动到0,和0移动到2,进行了一样的操作,交换0和2的位置)

我们以空格(0号棋子)为操作对象,将其与周围棋子交换位置。求解棋子移动过程的问题可以转化为求空白格(0号棋)移动过程。(如下图1,0可以和他周围的2,8,6,4交换位置,图2,0可以和他周围的1,2,3交换位置,图3,0可以和他周围的1,8交换位置,)


0号棋子移动过程只涉及到上移,下移,左移,右移四条法则。根据移动法则,从初始状态出发可以建立搜索树,求解问题其实就是求解最短路径问题。

广度优先算法

求解最短路径的问题考虑使用广度优先搜索算法(BFS,其英文全称是Breadth First Search。),所有因为展开节点而得到的子节点都会被加进一个先进先出的队列中。一般的实验里,其邻居节点尚未被检验过的节点会被放置在一个被称为 open 的容器中(例如队列或是链表),而被检验过的节点则被放置在被称为 closed 的容器中。(open-closed表)

1.算法执行过程

2.为算法实现的概念图:(黑色加粗数字为节点拓展顺序)

3.算法的优点:
广度优先搜索算法对于解决最短路径问题非常有效,搜索深度较小,每个节点只访问一次,节点总是以最短的结点总是以最短路径被访问,所以第二次路径确定不会比第一次短。

4.算法的缺点
广度优先搜索算法坚决最短路径问题虽然非常有效,但是解决问题需要非常庞大的内存空间,当路径较长或者节点过多时,会有非常巨大的内存开销,并且运行时间会非常长。
坚决方案:当节点数达到一定值时,默认该问题无解,停止算法。

编程环境及语言

语言:c++
环境:vs2019

代码实现

定义相关节点结构体:

定义相关变量和函数:

核心函数实现:

核心函数核心算法实现:

算法设置目标状态:

代码详情

/*
==============================================================广度优先算法解决8数码问题
==============================================================输入示例: 1_3_2_4_5_7_6_8_0[回车]   (下划线表示空格)
对应的8数码九宫格状态    |1|3|2|                           |4|5|7|                           |6|8|0|  目标状态            |1|2|3||4|5|6||7|8|0|【 0 表示九宫格的空白格 】
==============================================================*/
#include <iostream>
using namespace std;#define MAX_OPEN_LEN 50000
#define MAX_CLOSE_LEN 50000struct Snode//节点结构体
{int parent;  //指向该结点父节点的编号int map[9];
public:void In(const int* d);void Out(int* d);
};
void Snode::In(const int* d)
{for (int i = 0; i < 9; ++i)map[i] = d[i];
}Snode OPEN[MAX_OPEN_LEN];//OPEN表
int op = 0;
Snode CLOSE[MAX_CLOSE_LEN];//close表
int cp = 0;                //扩展的节点数
int result[50000][9];     //result数组用于保存路径int YONNEW(Snode& , Snode& );     //判断是否为新节点        返回值 1: 是  0: 不是
int FIND(const int* );         //广度优先运行函数
inline void  CHANGE(int& , int& );//交换俩个数
int JODER(Snode& );        //判断节点是否为目标节点  返回值 1: 是  0: 不是int main(void)
{int m[9] = {0};//初始化cout << "==============================================================" << endl;cout << "                    广度优先算法解决8数码问题                 " << endl;cout << "==============================================================" << endl;cout << "示例: 1_3_2_4_5_7_6_8_0[回车]   (下划线表示空格)          "  << endl;cout << endl;cout << "对应的8数码九宫格状态   |1|3|2|  目标状态:  |1|2|3|          " << endl;cout << "                        |4|5|7|              |4|5|6|          " << endl;cout << "                        |6|8|0|              |7|8|0|          " << endl;cout << endl;cout << "【注意】工程生产节点多于10000个视为无解                       " << endl;cout << "==============================================================" << endl;cout << "成功案例参考 :[123564780]  [123456780]                           " << endl;cout << "失败案例参考 :[756482310]  [156234780] " << endl;cout << "==============================================================" << endl;cout << "请按照示例输入8数码初始状态:";for (int i = 0; i < 3; i++)//输入for (int j = 0; j < 3; j++)cin >> m[3 * i + j];FIND(m);//运行return 0;
}int YONNEW(Snode& node1, Snode& node2)  //判断是否为新节点
{int f = 1;for (int i = 0; i < 9; i++){if (node1.map[i] != node2.map[i]) f = 0;}return f;
}inline void CHANGE(int& a, int& b)//交换俩个数
{int t = a;a = b;b = t;
}int JODER(Snode& node)//判断节点是否为目标节点
{int f = 1;int g[9] = { 1,2,3,4,5,6,7,8,0};//目标节点for (int i = 0; i < 9; i++){if (node.map[i] != g[i])f = 0;}return f;
}int FIND(const int* d)//运行函数
{int begin = 0;                    //begin含义是每次从OPEN表中去除要扩展的那个节点int node_number = 1;              //扩展节点数,初始时已有OPEN[0]节点,故为1static int dp[4] = { -3,-1,1,3 }; //-3上,3下,-1左,1右op = 1;cp = 0;OPEN[begin].In(d);OPEN[begin].parent = -1;  //OPEN表不为空while (op > 0){int i = 0, KONGE, pos, j = 0, k = 0;//找目标节点if (JODER (OPEN[begin]) == 1)  {cout << endl;cout << endl;cout << "==============================================================" << endl;cout <<  endl;cout << "                    成功得到正确解,路径如下:                " << endl;cout << endl;cout << "———————————————————————————————" << endl;CLOSE[cp] = OPEN[begin];//路径存入数组result中,目标节点--->根节点while (begin != -1)         {for (int i = 0; i < 9; i++){result[j][i] = OPEN[begin].map[i];}j = j + 1;begin = OPEN[begin].parent;}//result数组中路径输出,根节点--->目标节点for (i = j - 1; i >= 0; i--)       {for (k = 0; k < 9; k++){cout << result[i][k] << " ";if (k % 3 == 2)  cout << endl;}cout << endl;}cout << "=============================================================="  << endl;cout << "生成的节点总数为           ||           " << node_number << endl;cout << "扩展的节点总数为:         ||           " << cp << endl;cout << "==============================================================" <<  endl;return 1;}for (KONGE = 0; KONGE < 9; ++KONGE){if (OPEN[begin].map[KONGE] == 0)break;                        //跳出当前for循环,向下执行}for (i = 0; i < 4; ++i){   //判断空白位置位置怎样可以移动,与上边的判断相同if (KONGE == 0 && (i == 0 || i == 1))  continue;     if (KONGE == 1 && i == 0)         continue;if (KONGE == 2 && (i == 0 || i == 2))  continue;if (KONGE == 3 && i == 1)         continue;if (KONGE == 5 && i == 2)         continue;if (KONGE == 6 && (i == 1 || i == 3))  continue;if (KONGE == 7 && i == 3)         continue;if (KONGE == 8 && (i == 2 || i == 3))  continue;pos = KONGE + dp[i];//交换位置CHANGE(OPEN[begin].map[KONGE], OPEN[begin].map[pos]); Snode child;child.In(OPEN[begin].map);//判断是否为新节点for (j = 0; j < cp; ++j)      {if (YONNEW(CLOSE[j], child) == 1)break;}//得到新节点if (j == cp)                         {OPEN[op] = child;             //先使用op,再op加1OPEN[op].parent = begin;op++;node_number++;//无解,这里当op等于10000时退出,并返回0if (node_number == 10000)                             //无解,这里当op等于10000时退出,并返回0{cout << endl;cout << endl;cout << "==============================================================" << endl;cout << endl;cout << "           警告:                节点过多视为无解             " << endl;cout << endl;cout << "==============================================================" << endl;return 0;}}//前边把OPEN[min]的值进行了交换,现在再换回去,保持OPEN[min]的map数组CHANGE (OPEN[begin].map[KONGE], OPEN[begin].map[pos]);    }CLOSE[cp++] = OPEN[begin];begin = begin + 1;}return 0;
}

算法测试

算法输入初始状态:

测试结果


如上图,理论结果与算法结果一致,算法适应性较好。

算法其他运行实例
设置目标状态为:

1.成功案例
(1)初始状态为 123456780

(2)初始状态为 123564780


2.失败案例
(1)初始状态为 123564780

(2)初始状态为756482310

心得体会

设计算法解决问题的过程一定要抓住核心,定好操作对象,才能更好的解决问题。从算法到代码实现的过程也是一个复杂的过程,需要用到很多其他的知识储备比如数据结构等等。

希望这篇文章可以帮助刚接触算法的同学更好的理解广度优先算法。同时也希望自己可以在编程这条路上有所成就。

广度优先算法解决8数码问题【c++】相关推荐

  1. A*算法解决八数码问题 Java语言实现

    A*算法解决八数码问题 Java语言实现 参考文章: (1)A*算法解决八数码问题 Java语言实现 (2)https://www.cnblogs.com/beilin/p/5981483.html ...

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

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

  3. Python实现A*算法解决N数码问题

    Python实现A*算法解决N数码问题 A*算法的描述 A*算法的步骤 问题描述 代码以及测试结果 算法优势 算法存在一些不足 A*算法的描述 A*算法是BFS的一个变种,它把原来的BFS算法的无启发 ...

  4. Python利用A*算法解决八数码问题

    资源下载地址:https://download.csdn.net/download/sheziqiong/86790565 资源下载地址:https://download.csdn.net/downl ...

  5. Astar、A星算法解决八数码问题--python实现

    一.问题描述 数码问题又称9宫问题,与游戏"华容道"类似.意在给定的3*3棋格的8个格子内分别放一个符号,符号之间互不相同,余下的一格为空格.并且通常把8个符号在棋格上的排列顺序称 ...

  6. A*算法解决8数码问题python实现

    1.A*的通俗理解 很多游戏特别是rts,rpg类游戏,都需要用到寻路.寻路算法有深度优先搜索(DFS),广度优先搜索(BFS),A星算法等,而A星算法是一种具备启发性策略的算法,效率是几种算法中最高 ...

  7. Nilsson's sequence score算法解决八数码问题解释

    解决了最近一个人工智能关于解决八数码难题的作业. 图可能看不清,除了黑块外其他位置是英文字母ABCDEFGH A*:f(n)=g(n)+h(n) 其中f为总花费,g为已知花费(深度),h为估计花费 关 ...

  8. 全局择优搜索、A*算法、宽度优先算法解决八数码问题

    1问题描述 使用盲目搜索中的宽度优先搜索算法或者使用启发式搜索中的全局择优搜索或A算法,对任意的八数码问题给出求解结果.例如:对于如下具体的八数码问题: 通过设计启发函数,编程实现求解过程,如果问题有 ...

  9. A*算法解决八数码问题 人工智能原理实验报告 启发式搜索 python

    目录 一.实验主要步骤 ①.设计界面输入规则 ②.判断是否有解 ③.求解 二.实验结果展示 三.附录 完整实验程序代码: 一.实验主要步骤 ①.设计界面输入规则 有且仅有9位数字代表数码和空格,从左到 ...

最新文章

  1. 【hibernate系列】采用p6spy+SQLProfiler完整显示hibernate的S...
  2. Kail Linux渗透测试教程之免杀Payload生成工具Veil
  3. jpa怎么传参到in中_Spring Boot中的测试
  4. TensorRT学习笔记5 - 运行fc_plugin_caffe_mnist
  5. Win10安装后必做的优化,解决磁盘100%占用
  6. COALESCE()、isnull()、nullif()函数的用法
  7. Nginx 最全操作总结
  8. mysql date compare_SQLDataCompare下载
  9. Spring组合注解与元注解
  10. 寄存器间接寻址缺点_详解西门子间接寻址之地址寄存器间接寻址
  11. mysql打开数据库的sql语句_数据库MySQL——SQL语句(命令)
  12. 计算机专业所需的职业道德,浅议计算机职业道德
  13. 普通人翻身的希望?揭秘“元宇宙”到底是个啥玩意!
  14. 出海季,互联网出海锦囊之本地化
  15. 无向图全局最小边割集
  16. 站住!不许动!放下DOCTYPE!
  17. 最好的vsftpd配置教程
  18. 全网招募P图高手!阿里巴巴持续训练鉴假AI
  19. 杀戮空间2开服服务器架设教程UE3Redist
  20. 如何用Python检查回文对联(字符串)

热门文章

  1. python网络爬虫到底合不合法?怎么样才算合法?
  2. MATLAB机器人工具箱3-及轨迹规划
  3. 感恩节福利在这,拿走!
  4. webpack file-loader和url-loader
  5. 考研政治1000题浓缩版
  6. 联想扬天 P880 参数 联想扬天 P880怎么样
  7. “学习网站”懂得都懂
  8. Python环境变量搭建
  9. 相册程序mageVue
  10. 如何判断是否被百度K站