题目2:隐式图的搜索问题(A*算法解决八数码)
数据结构课程实践系列
题目1:学生成绩档案管理系统(实验准备)
题目2:隐式图的搜索问题(A*算法解决八数码)
题目3:文本文件单词的检索与计数(实验准备)
文章目录
- 数据结构课程实践系列
- 题目1:学生成绩档案管理系统(实验准备)
- 题目2:隐式图的搜索问题(A*算法解决八数码)
- 题目3:文本文件单词的检索与计数(实验准备)
- 声明
- 题目要求
- 何为八数码?
- 状态如何表示
- 所需知识
- 导出所需知识
- 优先队列BFS算法缺陷
- A*搜索算法
- 总结:
- 实际操作
- 搜索过程描述
- 启发式策略工作工程:红圈数字表示扩展顺序
- 代码实现
- Map+BFS+A*
- Hash+BFS+A*
- GAMEOVER
声明
题目要求
看过这次实验要求之后
总结:利用A*来解决八数码问题,状态很好找,每次移动空格就会形成一种新的状态,
何为八数码?
八数码游戏包括一个3X3的棋盘,棋盘上摆放着8个数字的棋子,留下一个空位。与空位相邻的棋子可以滑动到空位中。游戏的目的是要达到一个特定的目标状态。标注的形式化如下(举例):
2 | 3 | |
---|---|---|
1 | 8 | 4 |
7 | 6 | 5 |
(初始状态)
1 | 2 | 3 |
---|---|---|
8 | 4 | |
7 | 6 | 5 |
(目标状态)
状态如何表示
- 每个状态都用3*3的数组表示,但是BFS中需要入队出队,比较麻烦而且空间占用较大
- 状态压缩,采用一个整数保存状态的数字序列,例如状态1表示为203184765,状态2表示为123804765
所需知识
优先队列BFS算法,因为A*算法就是带有估价函数的优先队列BFS。
导出所需知识
优先队列BFS算法缺陷
该算法维护了一个优先队列(二叉堆),不断从堆中取出“当前代价最小”的状态(堆顶)去进行扩展。但是它得到只是初态到该状态的最小代价(并没有去考虑从该状态出发到目标状态的情况)
举例说明:
如果给定一个“目标状态”,需要求出从初态到目标状态的最小代价,优先队列BFS显然不行。因为一个状态的当前代价最小,只能说明从起始状态到该状态的代价很小,而在未来的探索中,从该状态到目标状态可能会花费很大的代价;另外一些状态虽然当前代价略大,但是未来到目标状态的代价可能会很小,于是从起始状态到目标状态的总代价反而更优。
A*搜索算法
于是,我们为了解决上面的问题:可以对未来可能产生的代码进行预估。详细地讲,我们去设计一个**“估价函数”**,以任意状态为输入,计算出从该状态到目标状态所需代价的估计值。在搜索之中,仍然维护了一个堆,不断从堆中取出“当前代价+未来估价”最小的状态来进行扩展。
为了保证第一次从堆中取出目标状态时得到的就是最优解,我们设计的估价函数需要满足一个基本准则:
设当前状态state到目标状态所需代价的估计值为f(state);设在未来的探索中,实际求出的从当前状态state到目标状态的最小代价为g(state)
对于任意的state,应该有f(state)<=g(state)
也就是说,估价函数的估值不能大于未来实际代价,估价比实际代价更优。估价函数f(n)=g(n)+h(n)
总结:
这种带有估价函数的优先队列BFS就成为A* 算法。只要保证对于任意状态state,都有f(state)<=g(state),A* 算法就一定能在目标状态第一次从堆中被取出时得到最优解,并且在搜索过程中每个状态只需要扩展一次(之后再被取出就可以直接忽略 )。估价f(state)越准确,越接近g(state),A*算法的效率越高。如果估价始终为0,就等于普通的优先队列BFS。
实际操作
搜索过程描述
A算法又称为启发式搜索算法。对启发式搜索算法,又可根据搜索过程中选择扩展节点的范围,将其分为全局择优搜索算法和局部择优搜索算法。
在全局择优搜索中,每当需要扩展节点时,总是从 Open 表的所有节点中选择一个估价函数值最小的节点进行扩展。其搜索过程可能描述如下:
- 把初始节点 S0 放入 Open 表中, f(S0)=g(S0)+h(S0) ;
- 如果 Open 表为空,则问题无解,失败退出;
- 把 Open 表的第一个节点取出放入 Closed 表,并记该节点为 n ;
- 考察节点 n 是否为目标节点。若是,则找到了问题的解,成功退出;
- 若节点 n 不可扩展,则转到第 (2) 步;
- 扩展节点 n ,生成子节点 ni ( i =1,2, …… ) ,计算每一个子节点的估价值 f( ni ) ( i =1,2, …… ) ,并为每一个子节点设置指向父节点的指针,然后将这些子节点放入 Open 表中;
- 根据各节点的估价函数值,对 Open 表中的全部节点按从小到大的顺序重新进行排序;
- 转第 (2) 步。
这里采用的启发式策略为:f(n) = g(n) + h(n),其中g(n)为从初始节点到当前节点的步数(层数),h(n)为 当前节点 “不在位 ”的方块数(也就是说不在位的方块数越少,那么临目标状态越近)例如下图中的h(n)=5,有的讲解的是不包含空格,我这里是包含了的,经测试只要前后标准一致,包不包含空格都一样。
g(n)为已经消耗的实际代价,即已经走了的步数。
h(n)为预测路径,即还有几个数字待走。
h(n)=5
启发式策略工作工程:红圈数字表示扩展顺序
代码实现
Map+BFS+A*
#include<cstdio>
#include<queue>
#include<map>
using namespace std;
char arr[10], brr[10] = "123804765";
struct node {int num, step, cost, zeroPos;bool operator<(const node& a)const {return cost > a.cost;}node(int n, int s, int p) {num = n, step = s, zeroPos = p;setCost();}void setCost() {char a[10];int c = 0;sprintf(a, "%09d", num);for (int i = 0; i < 9; i++)if (a[i] != brr[i])c++;cost = c + step;}
};
int des = 123804765;
int changeId[9][4] = { {-1,-1,3,1},{-1,0,4,2},{-1,1,5,-1},{0,-1,6,4},{1,3,7,5},{2,4,8,-1},{3,-1,-1,7},{4,6,-1,8},{5,7,-1,-1} };
map<int, bool>mymap;
priority_queue<node> que;//优先级队列
void swap(char* ch, int a, int b) { char c = ch[a]; ch[a] = ch[b]; ch[b] = c; }
int bfsHash(int start, int zeroPos) {char temp[10];node tempN(start, 0, zeroPos);//创建一个节点 que.push(tempN);//压入优先级队列 mymap[start] = 1;//标记开始节点被访问过 while (!que.empty()) {tempN = que.top();que.pop();//弹出一个节点 sprintf(temp, "%09d", tempN.num);int pos = tempN.zeroPos, k;for (int i = 0; i < 4; i++) {if (changeId[pos][i] != -1) {swap(temp, pos, changeId[pos][i]);sscanf(temp, "%d", &k);if (k == des)return tempN.step + 1;if (mymap.count(k) == 0) {node tempM(k, tempN.step + 1, changeId[pos][i]);que.push(tempM);//创建一个新节点并压入队列 mymap[k] = 1;}swap(temp, pos, changeId[pos][i]);}}}
}
int main() {int n, k, b;scanf("%s", arr);for (k = 0; k < 9; k++)if (arr[k] == '0')break;sscanf(arr, "%d", &n);b = bfsHash(n, k);printf("%d步即可变换完成", b);return 0;
}
所得结果跟我们上图分析结果一样,
changeId[9][4] = { {-1,-1,3,1},{-1,0,4,2},{-1,1,5,-1},{0,-1,6,4},{1,3,7,5},{2,4,8,-1},{3,-1,-1,7},{4,6,-1,8},{5,7,-1,-1} };
这个数组也就代表九个位置中四个方向的可置换的数组元素下标(-1表示该方向不能交换),注意:这里的四个方向的话,是逆时针,(上左下右)
Hash+BFS+A*
#include<cstdio>
#include<queue>
using namespace std;
char arr[10],brr[10]="123804765";
struct node{int num,step,cost,zeroPos;bool operator<(const node &a)const{return cost>a.cost;}node(int n,int s,int p){num=n,step=s,zeroPos=p;setCost();}void setCost(){char a[10];int c=0;sprintf(a,"%09d",num);for(int i=0;i<9;i++)if(a[i]!=brr[i])c++;cost=c+step;}
};
int changeId[9][4]={{-1,-1,3,1},{-1,0,4,2},{-1,1,5,-1},{0,-1,6,4},{1,3,7,5},{2,4,8,-1},{3,-1,-1,7},{4,6,-1,8},{5,7,-1,-1}};
const int M=2E+6,N=1000003;//362897;
int hashTable[M];//hashtable中key为hash值,value为被hash的值
int Next[M],des=123804765;//next表示如果在某个位置冲突,则冲突位置存到hashtable[next[i]]
priority_queue<node> que;//优先级队列
int Hash(int n){return n%N;
}
bool tryInsert(int n){int hashValue=Hash(n);while(Next[hashValue]){//如果被hash出来的值得next不为0则向下查找 if(hashTable[hashValue]==n)//如果发现已经在hashtable中则返回false return false; hashValue=Next[hashValue];}//循环结束hashValue指向最后一个hash值相同的节点 if(hashTable[hashValue]==n)//再判断一遍 return false; int j=N-1;//在N后面找空余空间,避免占用其他hash值得空间造成冲突 while(hashTable[++j]);//向后找一个没用到的空间 Next[hashValue]=j;hashTable[j]=n;return true;
}
void swap(char* ch,int a,int b){char c=ch[a];ch[a]=ch[b];ch[b]=c;}int bfsHash(int start,int zeroPos){char temp[10];node tempN(start,0,zeroPos); que.push(tempN);while(!que.empty()){tempN=que.top();que.pop();sprintf(temp,"%09d",tempN.num);int pos=tempN.zeroPos,k;for(int i=0;i<4;i++){if(changeId[pos][i]!=-1){swap(temp,pos,changeId[pos][i]);sscanf(temp,"%d",&k);if(k==des)return tempN.step+1;if(tryInsert(k)){//插入新状态成功,则说明新状态没有被访问过 node tempM(k,tempN.step+1,changeId[pos][i]);que.push(tempM);}swap(temp,pos,changeId[pos][i]);}}}
}
int main(){int n,k,b=0;scanf("%s",arr);for(k=0;k<9;k++)if(arr[k]=='0')break;sscanf(arr,"%d",&n);if(n!=des)b=bfsHash(n,k);printf("%d步即可变换完成",b); return 0;
}
GAMEOVER
题目2:隐式图的搜索问题(A*算法解决八数码)相关推荐
- 题目2:隐式图的搜索问题(实验准备)
题目2:隐式图的搜索问题(实验准备) 实验内容 实验要求 编程语言的选择 项目思路 项目解析 算法选择 A*算法 实验内容 对九宫重排问题,建立图的启发式搜索求解方法: 用A*算法求解九宫重排问题. ...
- 《数据结构课程实践》_02_隐式图的搜索问题_准备工作
02_隐式图的搜索问题_准备工作 一.实验题目与要求 二.编程语言以及开发环境 三.实验思路 A*算法 四.预习小结 一.实验题目与要求 实验要求: 对九宫重排问题,建立图的启发式搜索求解方法: 用A ...
- 《数据结构课程实践》_02_隐式图的搜索问题_实现
02_隐式图的搜索问题_实现 一.实验题目 二.编程语言以及开发环境 三.源代码 1.main类 2.节点类 3.算法类 四.运行结果 五.实验小结 一.实验题目 实验要求: 对九宫重排问题,建立图的 ...
- 2.隐式图的搜索问题
题目2:隐式图的搜索问题 实验内容 对九宫重排问题,建立图的启发式搜索求解方法: 用A*算法求解九宫重排问题. 实验要求 3х3九宫棋盘,放置数码为1~8的8个棋子,棋盘中留有一个空格,空格周围的棋子 ...
- 隐式图的搜索问题(九宫重排)——实验准备
隐式图的搜索问题(九宫重排)--实验准备 隐式图的搜索问题(九宫重排) 实验任务 实验要求 A*算法 隐式图的搜索问题(九宫重排) 实验任务 对九宫重排问题,建立图的启发式搜索求解方法. 用A*算法求 ...
- 隐式图的搜索问题(九宫重排)——项目实现
隐式图的搜索问题(九宫重排)--项目实现 隐式图的搜索问题(九宫重排)--项目实现 源代码 运行结果 隐式图的搜索问题(九宫重排)--项目实现 源代码 package SearchPath;publi ...
- 全局择优搜索、A*算法、宽度优先算法解决八数码问题
1问题描述 使用盲目搜索中的宽度优先搜索算法或者使用启发式搜索中的全局择优搜索或A算法,对任意的八数码问题给出求解结果.例如:对于如下具体的八数码问题: 通过设计启发函数,编程实现求解过程,如果问题有 ...
- 实践项目—隐式图的搜索(预习报告)
文章目录 实验内容 实验要求 编程语言及开发环境 实验思路 一.A*算法 二.A*算法解决九宫格问题 实验内容 1.对九宫重排问题,建立图的启发式搜索求解方法. 2.用A*算法求救九宫重排问题. 实验 ...
- 题目2:隐式图的搜索问题(A*算法解决八数码)代码实现
从起点 开始,把它加入到一个由方格组成的open list(开放列表) 中,这个open list像是一个购物清单.Open list里的格子是可能会是沿途经过的,也有可能不经过.因此可以将其看成一个 ...
最新文章
- 为树莓派安装远程桌面服务
- linux内核网络协议栈--数据包的网卡驱动收发包过程(二十五)
- 数据集合 oracle,oracle集合
- 敏捷宣言和企业Scrum作者Mike Beedle去世
- 编写junit 测试_编写JUnit测试的另一种方法(Jasmine方法)
- 用python偷偷给班级群女同学的颜值进行排名,排最后的 说开学要打爆我
- HTML表格设计用到哪些标签,网页设计:HTML表格标签
- 用crontab、crond在嵌入式系统中添加定时任务
- python第五章课后答案5.8_Python语言程序设计(美-梁勇)第5章习题解答
- 十大排序算法——快速排序法【挖坑法、左右指针法、前后指针法和优化方式三路快排】(C语言)
- 数据结构之求二叉树叶子结点个数
- class文件的反编译过程
- 论文|少样本学习综述
- 计算机操作系统的主要功能
- vue 关于图片和文字的绝对定位 js 动态设置定位
- Lancet Neurology:长期意识障碍的干预治疗
- java多线程死锁代码_java多线程死锁 编写高质量代码:改善Java程序的151个建议...
- 防灾科技学院图书馆大数据分析,2018读书报告丨来看一下谁是全年的阅读之星?
- Github上安卓榜排名第2的程序员教你如何学习【转载,侵删】
- 【webrtc】fdk-aac 编解码库cmake和 gn编译
热门文章
- python读取word文件并替换部分文字_python实现替换word中的关键文字(使用通配符)...
- python入门之控制结构-循环结构_Python 入门之控制结构 - 循环结构(一)
- CV:传统视觉知识—机器视觉系统的基础知识(机器视觉三要素+典型的工业机器视觉系统五大组件)
- AI公开课:19.03.06何晓冬博士《自然语言与多模态交互前沿技术》课堂笔记以及个人感悟
- AI机器人:机器人语音文本智能交互之自定义软件——实现模拟中本聪与V神跨时空畅谈
- ML之PLiR之LARS:利用LARS算法求解ElasticNet回归类型问题(实数值评分预测)
- 深入浅出统计学 第六章 排列与组合
- BigData预处理(完整步骤)
- 洛谷P1095守望者的逃离题解-伪动态规划/贪心
- UWP应用程序使用Prism框架构建MVVM