老师要求写一下八数码问题的三种解决方法,,,哎真的是苦了孩子了,只有在网上找找大佬们的代码来扩展了一下思路才勉强写出来,这里也分享一下自己的理解。

宽度优先与深度优先算法在八数码问题上的主要操作大同小异,主要的差别在于,带扩展节点扩展之后放在对列的前后的区别,宽度优先放在表后,保证一层一层递进式的处理。深度优先放在表前,保证当前节点能够优先扩展到达到深度界限为止。

从初始节点到目标节点一共需要26步,因此需要处理的时间比较长,在我自己电脑上的vs2019跑出来结果需要6200ms左右,当然这个时间还是可以接受的,而如果学会了启发式算法就不用这么多时间了。

核心代码如下(代码是以前在网上找的然后自己照着打然后改成自己容易理解的亚子了,侵删,侵删):

其中openTable存储带处理的节点,closeTable为已经处理的节点,使用 closeTable目的是方便存储路径。注:本来宽度优先搜索不需要range也就是深度优先的界限,因为是层层递进式的搜索,这里是非必要项,但是深度搜索中是需要的,避免单个节点一直搜索。

void bfs(deque<Node>& openTable, deque<Node>& closeTable, int range) {while (!openTable.empty()) {closeTable.push_back(openTable.front());openTable.pop_front();//节点n的深度是否等于深度界限if (closeTable.back().deep > range) {continue;}else {/*广度优先搜索和深度优先搜索的唯一区别就是子节点放到open表的位置:(1)广度优先搜索放到open表的后面(2)深度优先搜索放到open表的前面*/for (int j = 1; j <= 4; j++) {Node tempNode = closeTable.back();move(tempNode, j);//扩展节点nif (tempNode.code == "") {continue;}if (check_Visit(tempNode)) {continue;}tempNode.parent = closeTable.back().code;openTable.push_back(tempNode); //把其后裔节点放入OPEN表的前端            if (isGoal(tempNode)) {//是否有任何后继节点为目标节点cout << "成功,宽度优先找到结果:" << endl;showAnswer(closeTable);return;//break;}}}}
}

以下是代码的全文:

#include"bfs.h"
void bfs(deque<Node>& openTable, deque<Node>& closeTable, int range) {while (!openTable.empty()) {closeTable.push_back(openTable.front());openTable.pop_front();//节点n的深度是否等于深度界限if (closeTable.back().deep > range) {continue;}else {/*广度优先搜索和深度优先搜索的唯一区别就是子节点放到open表的位置:(1)广度优先搜索放到open表的后面(2)深度优先搜索放到open表的前面*/for (int j = 1; j <= 4; j++) {Node tempNode = closeTable.back();move(tempNode, j);//扩展节点nif (tempNode.code == "") {continue;}if (check_Visit(tempNode)) {continue;}tempNode.parent = closeTable.back().code;openTable.push_back(tempNode); //把其后裔节点放入OPEN表的前端            if (isGoal(tempNode)) {//是否有任何后继节点为目标节点cout << "成功,宽度优先找到结果:" << endl;showAnswer(closeTable);return;//break;}}}}
}int main() {clock_t start, finish;start = clock();init_Fact();string originString = "724506831";Node originNode;deque<Node> openTable, closeTable;//open存放未扩展节点,closed存放已扩展节点int range = 30;//深度界限originNode.code = originString;originNode.deep = 0;check_Visit(originNode);openTable.push_back(originNode);bfs(openTable, closeTable, range);cout << "open表使用大小:" <<openTable.size() << endl;cout << "close表使用大小:" << closeTable.size() << endl;finish = clock();cout << (finish - start) << "毫秒" << endl;//system("pause");return 0;
}
#pragma once
#include<iostream>
#include<ctime>
#include<queue>
#include<cstring>
#include<list>using namespace std;
const string GOAL = "012345678"; //254306781
int vis[362880 + 5], hashString[9];struct Node {string code;string parent;int deep;
};Node move(Node& tempNode, int x) {string::size_type loc;for (int i = 0; i < 9; i++) {if (tempNode.code[i] == '0') {loc = i;//0的位置,从0开始计数}}tempNode.deep++;if (x == 1) {//上移if (loc >= 3) {char tempString = tempNode.code[loc];//找到空格tempNode.code[loc] = tempNode.code[loc - 3];tempNode.code[loc - 3] = tempString;}else {tempNode.code = "";}}else if (x == 2) {//下移if (loc <= 5) {char tempString = tempNode.code[loc];//找到空格tempNode.code[loc] = tempNode.code[loc + 3];tempNode.code[loc + 3] = tempString;}else {tempNode.code = "";}}else if (x == 3) {//左移if (loc != 0 && loc != 3 && loc != 6) {char tempString = tempNode.code[loc];//找到空格tempNode.code[loc] = tempNode.code[loc - 1];tempNode.code[loc - 1] = tempString;}else {tempNode.code = "";}}else if (x == 4) {//右移if (loc != 2 && loc != 5 && loc != 8) {char tempString = tempNode.code[loc];//找到空格tempNode.code[loc] = tempNode.code[loc + 1];tempNode.code[loc + 1] = tempString;}else {tempNode.code = "";}}return tempNode;
}bool isGoal(Node tempNode) {//判断是否为最终的目标节点if (tempNode.code == GOAL) {return true;}return false;
}void show(string tempString) {//输出当前字符串if (!tempString.empty()) {cout << tempString[0] << " " << tempString[1] << " " << tempString[2] << endl<< tempString[3] << " " << tempString[4] << " " << tempString[5] << endl<< tempString[6] << " " << tempString[7] << " " << tempString[8] << endl << endl;}else {cout << "空的" << endl;}
}//路径
deque<Node> findPath(deque<Node>& closed) {deque<Node> dequeList;Node temp = closed.back();dequeList.push_back(temp);//closeTable表从后往前,根据parent值找到路径for (int i = closed.size() - 1; i >= 0; i--) {if (temp.parent == closed.at(i).code) {dequeList.push_back(closed.at(i));temp = closed.at(i);}}//cout << dequeList.size() << endl;return dequeList;
}void showAnswer(deque<Node>& closed) {deque<Node> way(findPath(closed));cout << "共需要" << way.size() << "步" << endl;for (int i = way.size() - 1; i >= 0; i--) {show(way.at(i).code);}//输出目标show(GOAL);
}void init_Fact() {hashString[0] = 1;for (int i = 1; i < 9; ++i) hashString[i] = hashString[i - 1] * i;memset(vis, 0, sizeof(0));
}
bool check_Visit(Node temp) {int nowString[9];int code = 0;for (int i = 0; i < 9; i++) {nowString[i] = temp.code[i] - '0';}for (int i = 0; i < 9; i++) {int cnt = 0;for (int j = i + 1; j < 9; ++j) if (nowString[j] < nowString[i]) cnt++;code += hashString[8 - i] * cnt;}if (vis[code]) return true;else vis[code] = 1;return false;
}

八数码问题的三种解决方式,其一:宽度优先搜索相关推荐

  1. Docker学习总结(44)——Docker容器时间与主机时间不一致的三种解决方式

    分享一个大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到人工智能的队伍中来!点击浏览教程 问题 我们在使用docker时发现Docker容器时间与主机时间经常出现不一致的情况 ...

  2. org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):的三种解决方式

    在使用mybatis-plus自定义SQL的时候,没有使用注解方式,而是将SQL语句写在mappper.xml文件中,就报了这个错:org.apache.ibatis.binding.BindingE ...

  3. 浏览器打开的网页被恶意篡改的三种解决方式 个人总结的最全的方式,亲测有效

    问题场景: 每次打开浏览器,都是2345或者360的网页,怎么改也改不掉,如下图: 在家里折腾了大半天,也百度了很多相关解决方案,但是都不全,这里我把自己总结的方式分享给大家 浏览器被2345或者36 ...

  4. spring同类调用事务不生效-原因及三种解决方式

    spring提供的声明式事务注解@Transactional,极大的方便了开发者管理事务,无需手动编写开启.提交.回滚事务的代码. 但是也带来了一些隐患,如果注解使用不当,可能导致事务不生效,最终导致 ...

  5. 八数码问题的三种解法

    北民大人工智能作业,其他相关作业资料和问题可留言交流   这里没有用课本上的open表和close表的方式,这个问题完全可以看图找规律解出来,而且三个代码(广度.A.A*)没有多少区别,代码相似度极高 ...

  6. 跨域问题常用的三种解决方式

    一.什么是跨域?跨域是如何产生的? 同源策略: 浏览器内置的规则!是浏览器提供的一种安全机制,限制来自不同源的数据.如果当前页面的URL地址和Ajax的请求地址不同源,浏览器不允许得到服务器的数据: ...

  7. 【App自动化测试】(八)三种等待方式——强制等待、隐式等待、显示等待

    目录 1. 为什么要添加等待? 2. 三种等待方式 3. 强制(直接)等待 4. 隐式等待 4.1 隐式等待说明 4.2 隐式等待无法解决的问题 5. 显式等待 5.1 为什么要使用显示等待机制? 5 ...

  8. oracle Hash Join及三种连接方式

    在Oracle中,确定连接操作类型是执行计划生成的重要方面.各种连接操作类型代表着不同的连接操作算法,不同的连接操作类型也适应于不同的数据量和数据分布情况. 无论是Nest Loop Join(嵌套循 ...

  9. 分布式锁简单入门以及三种实现方式介绍(滴滴)

    很多小伙伴在学习Java的时候,总是感觉Java多线程在实际的业务中很少使用,以至于不会花太多的时间去学习,技术债不断累积!等到了一定程度的时候对于与Java多线程相关的东西就很难理解,今天需要探讨的 ...

最新文章

  1. 水波纹效果,附工程源码
  2. matlab中max和find函数详解
  3. H3C PPP基本概念
  4. 性能调优:理解Set Statistics IO输出
  5. python3安装过程中出现的ssl问题,No module named _ssl或者renaming “_ssl“ since importing it failed
  6. plink源码_plink: 等位型计数(allele count)
  7. 奇安信代码安全实验室获授华为鲲鹏计算平台漏洞奖励计划合作伙伴
  8. [android] 百度地图开发 (两).所在地的城市定位和城市POI搜索
  9. 阶段1 语言基础+高级_1-3-Java语言高级_05-异常与多线程_第2节 线程实现方式_14_匿名内部类方式实现线程的创建...
  10. 2021 年 7 款优秀免费自动回复邮件工具(优缺点比较)
  11. ABAQUS混凝土CDP插件,一键生成混凝土CDP本构曲线
  12. ps抠图怎么放大图片_PS抠图时选区图片放大后,怎么移动图片抠图选区?
  13. 电商或财务系统计算钱精度的问题
  14. 第四讲 身份认证技术
  15. 智能无线网络的深度学习:一项综合调查
  16. 对敏捷管理模式核心价值的解读
  17. 关于uni-app中uni-forms表单验证时“多级结构对象数据”如何做数据校验的解决方案
  18. 作为一名大数据工程师你需要掌握Spark深度学习
  19. Outlook里怎么设置网易企业邮箱【163企业邮箱注册】
  20. 深度解析京东个性化推荐系统

热门文章

  1. 数值积分: 梯形规则--复合梯形规则--辛普森规则--复合辛普森规则--龙贝格求积公式
  2. 人工智能第八章答案神经网络,神经网络简答题
  3. 最全的厚黑学…教你怎样混社会
  4. C# FTP操作(上传、下载等……)
  5. spring源码解析,vip视频解析源码
  6. 电脑没有串口怎么办?
  7. 性能测试、操作系统优化对性能测试的影响,以及如何优化操作系统
  8. win7全屏_Win7系统截图的方法
  9. 滤波反投影重建算法(FBP)实现及应用(matlab)
  10. 绝对爆笑,虽然我知道可能和别的人雷同,但欢声笑语不雷同不是么?