Vijos 1360 - 八数码问题 - [A*]
优先队列BFS:
这个八数码问题本身其实是之前人工智能实验课的作业……
首先,如果不带估价函数,直接用优先队列BFS,肯定也是能得到正确结果的,至于用时怎么样,可以看评测结果……
代码:
#include<bits/stdc++.h>
using namespace std;
int dx[]={,,,-};
int dy[]={,-,,};
string ed="";
struct Node
{
int dist;
int x,y;
string mp; #define X(idx) (idx/3)
#define Y(idx) (idx%3)
char& val(int i,int j){return mp[i*+j];} void Zero()
{
for(int i=;i<;i++)
{
if(mp[i]!='') continue;
x=X(i), y=Y(i); break;
}
} bool operator<(const Node& o)const{return dist>o.dist;}
}st;
map<string,bool> vis;
priority_queue<Node> Q;
int main()
{
cin>>st.mp;
st.dist=;
st.Zero(); vis.clear();
Q.push(st), vis[st.mp]=;
while(Q.size())
{
Node now=Q.top(); Q.pop();
if(now.mp==ed)
{
cout<<now.dist<<endl;
break;
}
for(int k=;k<;k++)
{
Node nxt=now;
nxt.x+=dx[k], nxt.y+=dy[k], nxt.dist++;
if(nxt.x< || nxt.x> || nxt.y< || nxt.y>) continue;
swap(nxt.val(now.x,now.y),nxt.val(nxt.x,nxt.y));
if(!vis[nxt.mp]) Q.push(nxt), vis[nxt.mp]=;
}
}
}
评测结果:

Astar算法:
然后,我们知道,优先队列BFS里的优先队列,是一个维护当前代价的二叉堆,
我们接下来增加Astar算法的估价函数 $eval(x)$,考虑到要这个估价函数,是要不大于从当前状态到目标状态的实际代价的,
因此我考虑将其设定成:将当前状态下的九宫格看做一个长度为 $9$ 的字符串 $s$,目标状态也可以看做一个字符串 $t = "123804765"$,统计这两个字符串使得 $s_i \neq t_i$ 的 $i$ 的个数,记为 $e$,再取 $eval(x) = \lfloor \frac{e}{2} \rfloor$ 即可。
这也是很好理解的,因为不可能用更少的步数使得当前状态变为目标状态了。
AC代码:
#include<bits/stdc++.h>
using namespace std;
int dx[]={,,,-};
int dy[]={,-,,};
string ed="";
struct Node
{
int dist,eval;
int x,y;
string mp; #define X(idx) (idx/3)
#define Y(idx) (idx%3)
char& val(int i,int j){return mp[i*+j];} void Zero()
{
for(int i=;i<;i++)
{
if(mp[i]!='') continue;
x=X(i), y=Y(i); break;
}
} void Eval()
{
eval=;
for(int i=;i<;i++) eval+=(mp[i]!=ed[i]);
eval/=;
} bool operator<(const Node& o)const
{
return dist+eval>o.dist+o.eval;
}
}st;
map<string,bool> vis;
priority_queue<Node> Q;
int main()
{
cin>>st.mp;
st.dist=;
st.Zero();
st.Eval(); vis.clear();
Q.push(st), vis[st.mp]=;
while(Q.size())
{
Node now=Q.top(); Q.pop();
if(now.mp==ed)
{
cout<<now.dist<<endl;
break;
}
for(int k=;k<;k++)
{
Node nxt=now;
nxt.x+=dx[k], nxt.y+=dy[k], nxt.dist++;
if(nxt.x< || nxt.x> || nxt.y< || nxt.y>) continue;
swap(nxt.val(now.x,now.y),nxt.val(nxt.x,nxt.y));
if(!vis[nxt.mp])
{
nxt.Eval();
Q.push(nxt), vis[nxt.mp]=;
}
}
}
}
评测结果:

总结:
比较普通的优先队列维护下的BFS,和加了估价算法的Astar算法,可以明显看到时间和空间的使用都明显降低了。
(鉴于有可能会有同样在做这个实验的同学搜索到本文,我还是要声明一下:上面的两个代码都是我亲手敲的,没有看网上任何别的博客,想要拿去借鉴的同学,建议看懂了之后根据自己的思路做一些修改乃至优化……直接抄袭这样的事情最好还是不要做……)
Vijos 1360 - 八数码问题 - [A*]的更多相关文章
- vijos 1360 八数码问题 - 启发式搜索
背景 Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们. 描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0 ...
- 【宽搜】Vijos P1360 八数码问题
题目链接: https://vijos.org/p/1360 题目大意: 3x3格子上放1~8数字,一个空位,每次空位可与上下左右交换,固定终止布局,求输入的起始布局需要几步到达终止布局 题目思路: ...
- 关于八数码问题中的状态判重的三种解决方法(编码、hash、<set>)
八数码问题搜索有非常多高效方法:如A*算法.双向广搜等 但在搜索过程中都会遇到同一个问题.那就是判重操作(假设反复就剪枝),怎样高效的判重是8数码问题中效率的关键 以下关于几种判重方法进行比較:编码. ...
- A*算法 -- 八数码问题和传教士过河问题的代码实现
前段时间人工智能的课介绍到A*算法,于是便去了解了一下,然后试着用这个算法去解决经典的八数码问题,一开始写用了挺久时间的,后来试着把算法的框架抽离出来,编写成一个通用的算法模板,这样子如果以后需要用到 ...
- 八数码问题:C++广度搜索实现
毕竟新手上路23333,有谬误还请指正. 课程设计遇到八数码问题(这也是一坨),也查过一些资料并不喜欢用类函数写感觉这样规模小些的问题没有必要,一开始用深度搜索却发现深搜会陷入无底洞,如果设定了深度限 ...
- ACM/ICPC 之 BFS-广搜进阶-八数码(经典)(POJ1077+HDU1043)
八数码问题也称为九宫问题.(本想查查历史,结果发现居然没有词条= =,所谓的历史也就不了了之了) 在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同.棋盘上还有一个 ...
- BFS(八数码) POJ 1077 || HDOJ 1043 Eight
题目传送门1 2 题意:从无序到有序移动的方案,即最后成1 2 3 4 5 6 7 8 0 分析:八数码经典问题.POJ是一次,HDOJ是多次.因为康托展开还不会,也写不了什么,HDOJ需要从最后的状 ...
- 双向广搜+hash+康托展开 codevs 1225 八数码难题
codevs 1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Yours和zero在研究A*启 ...
- UVALive 6665 Dragonâs Cruller --BFS,类八数码问题
题意大概就是八数码问题,只不过把空格的移动方式改变了:空格能够向前或向后移动一格或三格(循环的). 分析:其实跟八数码问题差不多,用康托展开记录状态,bfs即可. 代码: #include <i ...
随机推荐
- java包名命名规范[【转】
indi : 个体项目,指个人发起,但非自己独自完成的项目,可公开或私有项目,copyright主要属于发起者. 包名为“indi.发起者名.项目名.模块名.……”. pers : 个人项目,指个人发 ...
- CentOS 7.4上网速度慢,修改DNS!
修改下DNS,vi /etc/resolv.conf 原来配置: nameserver 223.5.5.5 修改为: nameserver 114.114.114.114
- SNF软件开发机器人教程更新
SNF开发机器人教程:链接:https://pan.baidu.com/s/1Qpomg11c_1b1NKY5P7e4Bw 密码:jwc3
- blender show normals
https://blenderartists.org/forum/showthread.php?193096-Blender-2-5-how-to-show-normals-in-viewport
- php生成毫秒时间戳的例子
php时间函数time()生成当前时间的秒数,但是在一些情况下我们需要获取当前服务器时间和GMT(格林威治时间)1970年1月0时0分0秒的毫秒数,与Java中的currentTimeMilis()函 ...
- Atitit s2018.5 s5 doc list on com pc.docx v2
Atitit s2018.5 s5 doc list on com pc.docx Acc 112237553.docx Acc Acc 112237553.docx Acc baidu ne ...
- httpie的使用
安装 brew install httpie 使用 模拟提交表单 http -f POST yhz.me username=nate 显示详细的请求 http -v yhz.me 只显示Header ...
- 解决Chrome 70版本以后谷歌不再信任赛门铁克证书问题
Google 从 2018 年 10 月发布的 Chrome 70 就停止信任赛门铁克的旧证书了,而 Mozilla 也将在 10 月底发布 Firefox 63 时停止信任赛门铁克的旧证书. 导致大 ...
- caffe项目工程化封装FRCNN
各种坑!!想要做好,一定要自己一步步试,下载别人的总会出现各种问题. 步骤如下:(可以把这些文件打包在一个文件加下,分两个文件libs,include,一定要是自己的文件) 1 首先是配置caffe的 ...
- Python3 File
open() 方法 Python open() 方法用于打开一个文件,并返回文件对象,在对文件进行处理过程都需要使用到这个函数,如果该文件无法被打开,会抛出 OSError. 注意:使用 open() ...