文章目录

  • A*算法
    • 简介
    • 思路
    • A*伪代码
  • 八数码问题
    • 题目描述
    • 注意事项
  • 实验过程
    • 解决思路
      • 伪代码
      • 二维压缩为一维
      • 检查是否有解
      • 其他
    • 代码实现
    • h1和h2的对比
  • 关于曼哈顿距离
  • 参考链接

A*算法

简介

A*搜寻算法俗称A星算法。A*算法是比较流行的启发式搜索算法之一,被广泛应用于路径优化领域。它的独特之处是检查最短路径中每个可能的节点时引入了全局信息,对当前节点距终点的距离做出估计,并作为评价该节点处于最短路线上的可能性的量度。

思路

A*算法通过函数 f(n) = g(n)+h(n) 来计算每个节点的优先级。
f(n)是节点n的综合优先级。
g(n) 是节点n距离起点的代价。
h(n)是节点n距离终点的预计代价,这也就是A算法的启发函数。关于启发函数我们在下面详细讲解。
A
算法在运算过程中,每次从优先队列中选取f(n)值最小(优先级最高)的节点作为下一个待遍历的节点。另外,A*算法使用两个集合来表示待遍历的节点open_set,与已经遍历过的节点close_set。

A*伪代码

初始化open_set和close_set;
将起点加入open_set中,并设置优先级为0(优先级最高);
如果open_set不为空,则从open_set中选取优先级最高的节点n:如果节点n为终点,则:从终点开始逐步追踪parent节点,一直达到起点;返回找到的结果路径,算法结束;如果节点n不是终点,则:将节点n从open_set中删除,并加入close_set中;遍历节点n所有的邻近节点:如果邻近节点m在close_set中,则:跳过,选取下一个邻近节点如果邻近节点m也不在open_set中,则:设置节点m的parent为节点n计算节点m的优先级将节点m加入open_set中

八数码问题

题目描述

➢在一个3×3的九宫中有1-8这8个数字以及一个空格随机摆放在其中的格子里。将该九宫格调整到目标状态。
➢规则:每次只能将与空格(上、下、左、右)相邻的一个数字移动到空格中。试编程实现这一问题的求解。
➢备注:为了程序中表示方便,用0代替空格。
➢初始状态和目标状态:均由用户通过键盘手工输入或者从文件读入(不可以写死在程序里面)。
➢实验结果需要包含以下初始状态和目标状态的结果(check your answer:至少需要移动15步)。

注意事项

➢每个节点n需要记录父节点信息以及g(n)的值(已走过的步数)。
➢从当前状态到目标状态的代价估计h(n)可以从下面选一个(或者自拟)
h1(n):与目标相比, 错位的数字数目;
h2(n):曼哈顿距离总和( D(i,j)=|X1-X2|+|Y1-Y2| );
若是能对两种代价函数进行实验比较(同一初始状态下,两种代价函数导致的搜索步数的差异,需对多个初始状态进行实验),则更好。
➢每个状态的子状态最多四个(上、下、左、右移动),但要根据空格所处的实际位置确定当前状态具体有哪几个子状态。

实验过程

解决思路

伪代码

输入数据先检查是否一定有解。直接A*算法求解。输出结果

二维压缩为一维

需要注意的是,要把二维数组直接推平记录到字符串中,这样一来容易检查是否有解,而且更方便用open_set和close_set记录状态。
这样的话0号在二维数组中上下左右移动 就转换为 字符串中 与往前第三个字符互换位置,往0后第三个字符互换位置,相邻的互换位置

检查是否有解

若两个状态的逆序数奇偶性相同,则可相互到达,否则不可相互到达。
逆序数概念:

在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。也就是说,对于n个不同的元素,先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,当某两个元素的实际先后次序与标准次序不同时,就说有1个逆序。一个排列中所有逆序总数叫做这个排列的逆序数。

其他

set的使用
set里面会自动排序(从小到大)。重载结构体的小于号后,直接获取set第一个值就是当下优先级最高的。
记录路径的方法
没想到比较好的记录路径的方法,索性直接把路径存在每个状态结构体中。0上,1下,2左,3右

代码实现

#include<iostream>
#include<string>
#include<set>
#include<stack>
#include<map>
using namespace std;
bool check(string tem) {//目标状态的逆序数是0,所以如果该状态的逆序对是奇数,无解,返回1;string  s = "";int cnt = 0;for (auto i : tem) {if (i != '0')s += i;} int len = s.size();for (int i = 1; i < len; i++) {for (int j = 0; j < i; j++) {if (s[i] < s[j]) cnt++;}} return cnt%2;
}
struct Node {string status; //记录状态(可以推出h)string searchPath; //记录搜索路径int f; //记录优先级 int g; //搜索深度bool operator < (const Node& o)const {if(f!=o.f)return f < o.f; return status < o.status;}
};set<Node> openSet;
set<string> closeSet;
string target = "123456780";  //target为目标状态
string ansToString[] = { "向上移动","向下移动","向左移动","向右移动" };
string toChar = "0123";
int searchCnt = 0,H1Flag = 1;
int moveArray[4] = { -3,3,-1,1 };string calStatus(string status, int i) {int pos = 0;while (status[pos] != '0') pos++;int newPos = pos + moveArray[i];if ((pos < 3 && i == 0) || (pos > 5 && i == 1) || ((pos % 3) == 0 && i == 2) || ((pos % 3) == 2 && i == 3))  //不能上下左右移动return "";swap(status[pos], status[newPos]);return status;
}int h1(string status) {//错位数字的距离int cnt = 0,pos = 0;for (int i = 0; i < 9; i++) {if (status[i] != target[i]) cnt++;}return cnt;
}int h2(string status) {//计算曼哈顿距离int pos = 0;while (status[pos] != '0') pos++;return (8 - pos) / 3 + (8 - pos) % 3;
}Node A_Star(string myStatus) {//初始化Node startNode;startNode.status = myStatus;startNode.searchPath = "";startNode.f = 0; startNode.g = 0;openSet.insert(startNode);while (openSet.size()) { //取优先级最高的searchCnt++;//搜索次数记录Node tem = *openSet.begin(); openSet.erase(tem); if (tem.status == target)   return tem; elsecloseSet.insert(tem.status);//找下个状态for (int i = 0; i < 4; i++) {Node nextNode;nextNode.status = calStatus(tem.status, i);if (nextNode.status == "") continue; nextNode.searchPath = tem.searchPath + toChar[i];nextNode.g = tem.g + 1;if(H1Flag)nextNode.f = tem.g + h1(tem.status);elsenextNode.f = tem.g + h2(tem.status);if (closeSet.count(nextNode.status))continue;openSet.insert(nextNode);} }
}int main() {//输入数据string myStatus;for (int i = 0; i < 9; i++) {char c; cin >> c;myStatus += c;}//如果不合法直接结束if ( check(myStatus) ) { cout << "无解" << endl;return 0;}//输入合法,A*算法Node ans = A_Star(myStatus);//根据状态输出移动方式if (H1Flag)cout << "用曼哈顿距离做估计代价函数,";elsecout << "用不同数字位数做估计代价函数,";cout << "一共搜索了" << searchCnt << "次"<<endl;int len = ans.searchPath.size();for (int i = 0; i < len; i++) {cout << i+1 << ".空白格" << ansToString[ans.searchPath[i] - '0'] << endl;} return 0;
}/*
1 5 3
2 4 6
7 0 8//无解
2 1 3
4 5 6
7 8 0
*/

h1和h2的对比

h1用曼哈顿距离

h2用不同数字位数

总结:因为测试数据比较少了,很难说哪种估计代价的函数更优一些。

关于曼哈顿距离

让老师检查,发现之前的曼哈顿距离写错了。但是我发现这样的话,搜索次数相当高。

int h2(string status) {//计算曼哈顿距离,也就是计算1-8到真正位置的距离然后求和就好了。 int sum = 0;for (int i = 1; i < 9; i++) {int pos = 0;while ( status[pos] != '0'+i ) pos++;sum += ( (i - pos) / 3 + (i - pos) % 3 );}return sum;
}

参考链接

知乎 - 路径规划之 A* 算法
百度 - A*算法

人工智能作业 - A*算法程序求解八数码相关推荐

  1. 利用Python求解八数码难题

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

  2. 基于Python实现的AStar求解八数码问题

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

  3. 广州大学人工智能导论实验一(八数码问题)

    实验一 八数码问题 一. 实验目的 该课程的教学应贯彻理论与实践相结合的原则,为学生所学到的理论提供实践的场所,通过实验课程中具体问题的求解达到深入了解并掌握的目的. 二. 实验环境 微型计算机,操作 ...

  4. 人工智能:(C语言)采用状态空间法求解八数码问题

    实验要求:八数码难题也称九宫问题,它是在3×3的方格棋盘上,分别放置了表有数字1.2.3.4.5.6.7.8的八张牌,初始状态S0,目标状态Sg,要求程序能输入任意的初始状态和目标状态,要求通过空格来 ...

  5. 7种方法求解八数码问题

    [八数码问题]//https://vijos.org/p/1360 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要 ...

  6. 多种方法求解八数码问题

    AI的实验报告,改了改发上来.希望路过的大牛不吝赐教.非常是纳闷我的ida*怎么还没有双搜快.还有发现基于不在位启示的A*和Ida*都挺慢.尤其是ida* 搜索31步的竟然要十几秒.是我写的代码有问题 ...

  7. 人工智能实现a*算法解决八数码_小白带你学回溯算法

    微信公众号:小白算法 关注可了解更多算法,并能领取免费资料.问题或建议,请公众号留言;小白算法,简单白话算法,每个人都能看懂的算法 上一期算法回顾--贪婪法:https://mp.weixin.qq. ...

  8. 【人工智能实验】A*算法求解8数码问题

    目录 实验一 A*算法求解8数码问题 一.实验目的 二.实验原理 三.实验结果 四.实验总结 附录代码 推荐文章 实验一 A*算法求解8数码问题 一.实验目的 熟悉和掌握启发式搜索的定义.估价函数和算 ...

  9. 【人工智能】八数码问题:广度搜索、深度搜索

    应用广度搜索BFS和深度搜索DFS解决八数码问题,广度搜索和深度搜索都是盲目搜索,相关理论知识,算法过程:问题求解:状态空间图和盲目搜索. 参考:7种方法求解八数码问题 Python实现A*算法解决N ...

最新文章

  1. Bi-level error correction for PacBio long reads. PacBio长读数的两级纠错
  2. swift处理网络返回数据(封装)
  3. __weak与__block的区别
  4. java 延迟初始化_java-不正确的延迟初始化
  5. sqlserver附加数据库错误823的解决方案
  6. Linux下NFS(网络文件系统)的建立与配置方法
  7. JAVA多线程之扩展ThreadPoolExecutor
  8. iframe高度自适应,终于解决了
  9. 网络爬虫--1.通用爬虫和聚焦爬虫
  10. 深入解析:从源码窥探MySQL优化器
  11. 用java编写一个课表串口,安卓课程表源代码
  12. Codeforces 938.C Constructing Tests
  13. android5.1使用SerialManagerService
  14. 论软件架构建模技术与应用
  15. 【基站位置查询】通过lac,cellid进行手机基站位置查询和经纬度查询
  16. 电脑远程桌面连接怎么操作?
  17. 人工智能没成果,年底的PPT怎么写?腾讯科学家张潼离职的后续讨论
  18. 使用Windows 10自带工具 校验MD5 SHA1 SHA256类型文件
  19. html5制作毕业光盘,同学聚会的视频和照片编辑制作,最后刻录成光盘 每人一张(数据刻录)...
  20. Spark基础学习笔记06:搭建Spark On YARN集群

热门文章

  1. Linux虚拟机CentOS7挂机问题
  2. 深度学习之数据处理——如何将图片和标签打乱并划分为训练集和测试集
  3. 微信的服务器 上海,微信团队:上海机房服务器发生故障 个人账号安全暂不受影响...
  4. View Programming Guide for IOS:Views笔记
  5. 台式计算机联网,台式电脑怎么联网宽带
  6. 82. 采用 OPA5 开发支持页面跳转的 SAP UI5 集成测试用例
  7. perf part II
  8. python京东自动签到_利用python Selenium实现自动登陆京东签到领金币功能
  9. Linux系统无名管道通信实验,Linux进程间通信(二)---管道通信之无名管道及其基础实验...
  10. linux中如何查看文件上下文,linux通过grep根据关键字查找日志文件上下文