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 ...
随机推荐
- REST API 调用 方法
METHOD DESCRIPTION GET Retrieves the specified resource POST Creates a resource ...
- iOS - 统计代码行数
终端 -> 进入文件夹 查看每一行的行数 find . -name "*.m" -or -name "*.h" -or -name "*.xib ...
- Ant之build.xml配置详解【转】
原文:https://blog.csdn.net/mevicky/article/details/72828554 前言国内关于build.xml的配置资料太零散了,实在是受不了,故而将自己的笔记整理 ...
- java mqtt
代码: package cc.gongchang.mqtt; import java.net.URISyntaxException; import org.fusesource.hawtdispatc ...
- Typora的使用
Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式,其目标是实现易读易写.我刚刚接触一款简单高效的Markdown编辑器–Typora, ...
- MySql 建表、添加字段、修改字段、添加索引SQL语句写法及SQL索引
---------添加索引方法--------- .添加PRIMARY KEY(主键索引) mysql>ALTER TABLE `table_name` ADD PRIMARY KEY ( `c ...
- python 模块学习
一.from django.contrib.auth.hashers import make_password 通过函数名即可发现,主要有两个函数,分别是创建密码和验证 用法 ps = " ...
- SQL2008R2的 遍历所有表更新统计信息 和 索引重建
[2.以下是更新统计信息] DECLARE UpdateStatisticsTables CURSOR READ_ONLY FOR SELECT sst.name, Schema_name(sst.s ...
- Git入门到高级系列1-git安装与基础命令
视频课程地址 腾讯课堂 为什么要进行项目文件的版本管理 代码备份和恢复 团队开发和协作流程 项目分支管理和备份 git 是什么? git是一个分布式的版本控制软件.版本控制是一种记录一个或若干文件内容 ...
- Safari 3D transform变换z-index层级渲染异常的研究
by zhangxinxu from http://www.zhangxinxu.com/wordpress/?p=5569 一.Safari是新时代的IE6 在2年前介绍currentColor变量 ...