题目链接:https://vijos.org/p/1360

优先队列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*]的更多相关文章

  1. vijos 1360 八数码问题 - 启发式搜索

    背景 Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们. 描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0 ...

  2. 【宽搜】Vijos P1360 八数码问题

    题目链接: https://vijos.org/p/1360 题目大意: 3x3格子上放1~8数字,一个空位,每次空位可与上下左右交换,固定终止布局,求输入的起始布局需要几步到达终止布局 题目思路: ...

  3. 关于八数码问题中的状态判重的三种解决方法(编码、hash、&lt;set&gt;)

    八数码问题搜索有非常多高效方法:如A*算法.双向广搜等 但在搜索过程中都会遇到同一个问题.那就是判重操作(假设反复就剪枝),怎样高效的判重是8数码问题中效率的关键 以下关于几种判重方法进行比較:编码. ...

  4. A*算法 -- 八数码问题和传教士过河问题的代码实现

    前段时间人工智能的课介绍到A*算法,于是便去了解了一下,然后试着用这个算法去解决经典的八数码问题,一开始写用了挺久时间的,后来试着把算法的框架抽离出来,编写成一个通用的算法模板,这样子如果以后需要用到 ...

  5. 八数码问题:C++广度搜索实现

    毕竟新手上路23333,有谬误还请指正. 课程设计遇到八数码问题(这也是一坨),也查过一些资料并不喜欢用类函数写感觉这样规模小些的问题没有必要,一开始用深度搜索却发现深搜会陷入无底洞,如果设定了深度限 ...

  6. ACM/ICPC 之 BFS-广搜进阶-八数码(经典)(POJ1077+HDU1043)

    八数码问题也称为九宫问题.(本想查查历史,结果发现居然没有词条= =,所谓的历史也就不了了之了) 在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同.棋盘上还有一个 ...

  7. BFS(八数码) POJ 1077 || HDOJ 1043 Eight

    题目传送门1 2 题意:从无序到有序移动的方案,即最后成1 2 3 4 5 6 7 8 0 分析:八数码经典问题.POJ是一次,HDOJ是多次.因为康托展开还不会,也写不了什么,HDOJ需要从最后的状 ...

  8. 双向广搜+hash+康托展开 codevs 1225 八数码难题

    codevs 1225 八数码难题  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond   题目描述 Description Yours和zero在研究A*启 ...

  9. UVALive 6665 Dragon’s Cruller --BFS,类八数码问题

    题意大概就是八数码问题,只不过把空格的移动方式改变了:空格能够向前或向后移动一格或三格(循环的). 分析:其实跟八数码问题差不多,用康托展开记录状态,bfs即可. 代码: #include <i ...

随机推荐

  1. NOIP2010提高组 机器翻译

    OJ提交地址:https://www.luogu.org/problemnew/show/P1540 http://noi.openjudge.cn/ch0112/07/ 总时间限制: 1000ms  ...

  2. Servlet中的request对象、重定向和转发的差别(6)

    1.这里所说的request对象指的是HttpServletRequest对象,它代表client的请求,当client通过HTTP协议訪问server时.HTTP请求头中的全部信息都封装在这个对象中 ...

  3. 唯一ID算法之:snowflake(Java版本)

    Twitter开源的算法,简单易用. /** * Twitter_Snowflake<br> * SnowFlake的结构如下(每部分用-分开):<br> * 0 - 0000 ...

  4. C++ thread类多线程编程

    https://blog.csdn.net/dcrmg/article/details/53912941 多线程操作的thread类,简单多线程示例: #include <iostream> ...

  5. MySql 建表、添加字段、修改字段、添加索引SQL语句写法及SQL索引

    ---------添加索引方法--------- .添加PRIMARY KEY(主键索引) mysql>ALTER TABLE `table_name` ADD PRIMARY KEY ( `c ...

  6. SATA主机协议的FPGA实现之物理层设计

    SATA主机协议的FPGA实现之物理层设计   接上一篇文章,这里讲解SATA主机协议的物理层的实现过程. 下图是标准SATA协议文档中给出的物理层结构.可以看到它包含控制模块.时钟数据提取单元.同步 ...

  7. STM32串口DMA超时接收方法,可大大节约CPU时间

    //超时时间定义#define        UART1_TimeoutComp 2  //20ms#define        UART2_TimeoutComp 10  //100ms#defin ...

  8. fiddler 中显示请求 IP

    在 Rules -> Customize Rules... 中,static function Main() 中加一行 FiddlerObject.UI.lvSessions.AddBoundC ...

  9. 在Linux添加定时任务删除5天前的日志文件

    利用shell脚本自动清理,脚本如下 1.删除文件命令: find 对应目录 -mtime +天数 -name "文件名" -exec rm -rf {} \; 实例命令: fin ...

  10. 必读:Spark与kafka010整合

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/rlnLo2pNEfx9c/article/details/79648890 SparkStreami ...