题目描写叙述 Description

Yours和zero在研究A*启示式算法.拿到一道经典的A*问题,可是他们不会做,请你帮他们.

问题描写叙述



在3×3的棋盘上,摆有八个棋子,每一个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子能够移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765)。找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

输入描写叙述 Input Description

输入初试状态,一行九个数字,空格用0表示

输出描写叙述 Output Description

仅仅有一行,该行仅仅有一个数字,表示从初始状态到目标状态须要的最少移动次数(測试数据中无特殊无法到达目标状态数据)

例子输入 Sample Input

283104765

例子输出 Sample Output

4

血泪史,血泪史啊TUT

从昨天上午捣鼓,到今天一直跳了半个上午才弄好。然后我发现,我的代码能力真的很低下。不编译感觉什么事儿都没有,一调试N个错误,还都是细节上的粗心。逻辑上的失误。思路转换的时候忘了回溯什么的。看来我真得好好磨练代码能力了。

每一个题目都要自己敲,一不小心可能就有新的发现。

这道题思路还是比較简单的。之前一直纠结于如何存状态。事实上就用朴素的二维数组就能够。3*3不大。也不用传递数组形參或者实參,直接swap,回溯的时候再swap回来就能够了。

详细方法是:每次向上下左右四个方向交换空位和数字。判重,计算估价函数,进入优先队列,更新空位坐标和已走步数,直到找到解。

以下是一些细节上的说明:

1.判重 这个刚開始准备用哈希表,从没写过哈希表,但后来听了里奥神犇的建议用了set 并不慢 就这道题而言。每一个数字都是有0-9这九个数字组成,一共仅仅有三十万种状态,况且假设8个数字确定了最后一位也就确定了,用哈希是非常好的,不easy出现重叠冲突。

可是用set更加简明易行,直接计算数字insert进去就能够了,查找时能够用count函数检查。

2.估价函数eva:eva是evaluate 估价(动词) 或者evaluation 估价(名词)的缩写。

这次顺便学习了数学上和国际象棋上的三个距离:

曼哈顿距离:两点横坐标差点绝对值和纵坐标差的绝对值之和。

名字来源于曼哈顿的街道都是矩形网格状的,从某点到还有一点的距离就是曼哈顿距离。

欧拉距离:两点间的直线距离。计算公式是两点左边差绝对值的平方和。相当于已知三角形直角边求三角形最长边 

切比雪夫距离:两点横纵坐标差绝对值中较大的一个。

曼哈顿距离是求和。这里是取max。(让我想起某个诸城一中讲的离散化的题目) 

原本最准确应当採用曼哈顿距离。由于格子仅仅能上下左右移动。可是曼哈顿距离的计算我仅仅会最朴素的四次方求解,不知有没有简单方法。其实,在这里我们也能够用像骑士精神那道题里出现的推断与目标状态不同的各自有多少,这个是平方的复杂度,可是经模拟,效果是相同的。它相同满足估价函数值均不大于实际值。

因为估价函数满足假设估价函数值均不大于实际值,那么向估价函数小的方向进展一定能达到最优解。这一条我不知道怎样证明但已被证明。因此我们能够採用统计有多少个不同格子的估价做法。

3.一些细节。关于这道题目中我犯的N个错误

A.注意常量数组所实用的是大括号!。!(pas是小括号)

const int t[3][3]=
{{1,2,3},
{8,0,4},
{7,6,5}};

B.优先队列的重载。因为优先队列默认大的在前,假设想要让eva小的在前,应该把大于号重载成小于号。因为涉及STL(优先队列)。应当在后面加上const

bool operator < (node b) const
{
return eva>b.eva;
}

C.关于set版哈希的处理,这里是把每一个状态转化为一个int数字放入集合中

bool gethash(node &now)
{
int he=0;
for (int i=0;i<3;i++)
{
for (int j=0;j<3;j++)
{
he=he*10+now.a[i][j];
}
}
if (hash.count(he)) return false;
hash.insert(he);
return true;
//Èç¹ûûÓÐÕâ¸öÊý¾Í¹þÏ£ÁË·ñÔò·µ»Øfalse
}

再看以下原始状态的数字转化

for (int i=0;i<3;i++)
{
for (int j=0;j<3;j++)
{
e.a[i][j]=s[i*3+j]-'0';
if (e.a[i][j]==0)
{
e.x=i;
e.y=j;
}
he=he*10+e.a[i][j];
}
}

注意,以下是吧读入的字符转换为数字,而上面的数组中存储的本来就是数字,直接计算就能够了。然而我上面那个写成了now.a[i][j]-'0' 于是全是负数···于是set不会报反复···于是死循环···

D.bfs的细节问题(单步了N次TUT)

void bfs()
{
while (!q.empty())
{
if (ok) return;
node now=q.top();
q.pop();
int nx,ny;
for (int i=0;i<4;i++)
{
nx=now.x+xx[i];
ny=now.y+yy[i];
if (nx<0||nx>2||ny<0||ny>2) continue;
swap(now.a[nx][ny],now.a[now.x][now.y]);
if (!gethash(now))
{
swap(now.a[nx][ny],now.a[now.x][now.y]);
continue;
} //Çó¹þÏ£ ×¢ÒâÈç¹û²»³ÉÁ¢Ó¦·µ»ØÔ­À´µÄÖµ£¡£¡£¡
now.x=nx;
now.y=ny;
now.id++;
now.eva=geteva(now);//Çó¹À¼Ûº¯Êý
if (now.eva==now.id)
{
printf("%d\n",now.id);//×îÓÅÐÔ£¨²½Êý×îÉÙ£©³ÉÁ¢Ô­Àí£º¹À¼Ûº¯ÊýÖµ²»´óÓÚʵ¼ÊÖµ£¬Ôò½â±Ø¶¨×îÓÅ
ok=true;
break;
}
q.push(now);
now.x-=xx[i];
now.y-=yy[i];
swap(now.a[nx][ny],now.a[now.x][now.y]);
now.id--;
}
}
}

这是BFS部分的代码。代码应该非常好懂。

可是···

第一次。发现我改变了now之后没有回溯,于是非常多状态一时半会儿找不到。TLE···

第二次,发现空格的坐标在每一个状态中并没有更新,于是空格根本无法到达角格,输出无解(“= =”)···

第三次,发现我并没有把now这个节点的状态全然恢复到原来。id并没有--。导致步数紊乱仅仅增不减,WA···

第四次。发现假设出现了已经有过的状态。虽然判重没有问题仍然进入队列且其它状态被忽略···细致一看原来gethash返回false后直接continue并没有回溯。这样now在下一次循环的状态就延续了这个已经出现过的状态···死循环···

第五次,发现eva函数的返回值不大对,事实上应该返回已走步数+估价函数。可是我没有加已走步数,这道题小数据不受影响,可是后果慘重···

第六次,发现空格坐标更新后没有回溯···于是又调试···

凡此种种,吐血一上午,几近崩溃,于是和大家争论tarjan究竟应该读什么,后来听了音频。有道上念作tar zhen 恩 能够接受 然而我们居然一直没有看出前面的那个expression居然是深度广度优先搜索···

总之,吸取教训。以后要好好提高代码能力了

昨天上知乎又受到了教育·1··还是应该努力学习,好好读书。争取成为一名优秀的技宅和出色的学霸···rio君的故事好励志,所以还是要努力努力···文史哲个人修养也要提高。技术能力也要提高,家务能力也要提高,我要十项全能···什么鬼反正某人说过懂编程懂project又懂歌剧的人是非常有魅力的···

然后膜拜一下维特根斯坦···维特根斯坦这种名字可能真的要让人如雷贯耳不胜惶恐。恩我要努力成为这种文青。然而如今我却是这样想的:维特根斯坦小时候和希特勒在一起好萌啊【PIA飞 好吧这说明窝离文青还有非常遥远的距离又萌又腐咩【什么鬼 这些书总是要读的 既然提到维特根斯坦就顺便拜一拜罗素这种奇妙人物吧 这些大家族果然修养各种不凡啊···

然后再膜拜一下香浓,啊不正确。香农。

Shannon这个让我最先想到的是爱尔兰Limerick的那条河,多美的名字,好像去那儿···= =扯回来,既然隔壁小乔他们承认,那看来继图灵和冯诺依曼之后,香农也是相当伟大的人物了。有时候认为诺依曼费曼这种天才全才又是性情中人永远仅仅能被我们膜拜的,然而我们很多其它人终究不是天才,所以我还是开开心心地过我的生活吧。即使我们不是知识的开创者,我们也能够做知识的追随者。这并没有错。并且。我们也许没有如此耀眼的才华,但我们为何不能做一个这种性情中人呢。性情不是他们的专利。我们仅仅要敢想敢做也是能够的。又想到某剧里评价大学的一句话。如此充满理想主义与纵欲轻狂的一个地方。我认为,既然年轻就应该怀抱着理想主义,这种人生才干多彩。我读维特根斯坦,深深地体会到这样一点:仅仅要敢想敢做就能够。我们年轻。更不能在思想上受到束缚,我们应该敢去想,不管对错。茨威格十几岁的时候,生活在欧洲的心脏,在哪个二十世纪的黎明年代,维也纳的年轻人正是在这样一种文化价值全方位兴旺的环境熏陶下变得格外早熟而富有思想力。年轻的评论家们从不吝惜用属于自己的思想大胆解读文化,解读世界。维也纳和柏林那群十五六岁的少年的见地已经令整个欧洲震动。我们也许没有那传承千年的文化环境。没有图书馆和音乐会,但我们也能够努力去做。

文化的庸俗是由于人们甚至不愿去想。不愿去思考,仅仅是像虫豸一样碌碌于匆忙的地铁线上,年轻人为考试而反复在竞争中功利地生活,底层人们为生存而挣扎为物质而拼命,上层人们满足于安逸舒适的生活。奉行中庸之道和犬儒主义。把这些当做现实主义的生存之道。非常少有人再天真地做着自己所想的事情。理想主义也许在复杂的现实中早已磨灭,但我不希望在年轻人身上看不到这些理想主义的光辉。至少是对自身价值的承认和追求。我们应该思考,我们应该学习,我们应该进步,我们应该快乐。

好像不知不觉弄出来一篇奇怪的作文···还是抓紧回到正题把···

那么上代码吧

——卧龙跃马终黄土,人事音书漫寂寥

【基础练习】【BFS+A*】codevs1225八数码难题题解的更多相关文章

  1. codevs1225八数码难题(搜索·)

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

  2. codevs1225 八数码难题

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

  3. 洛谷 P1379 八数码难题 题解

    我个人感觉就是一道bfs的变形,还是对bfs掌握不好的人有一定难度. 本题思路: 大体上用bfs搜,用map来去重,在这里只需要一个队列,因为需要较少步数达到的状态一定在步数较多的状态之前入队列. # ...

  4. 习题:八数码难题(双向BFS)

    八数码难题(wikioi1225) [题目描述] 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出 ...

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

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

  6. Codevs 1225 八数码难题

    1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Yours和zero在研究A*启发式算法.拿到一道经典的 ...

  7. [luogu]P1379 八数码难题[广度优先搜索]

    八数码难题 ——!x^n+y^n=z^n 我在此只说明此题的一种用BFS的方法,因为本人也是初学,勉勉强强写了一个单向的BFS,据说最快的是IDA*(然而蒟蒻我不会…) 各位如果想用IDA*的可以看看 ...

  8. 洛谷P1379八数码难题

    题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中. 要求解的问题是:给出一种初始布局(初始状态)和目标布局(为 ...

  9. 洛谷——P1379 八数码难题

    P1379 八数码难题 双向BFS 原来双向BFS是这样的:终止状态与起始状态同时入队,进行搜索,只不过状态标记不一样而已,本题状态使用map来存储 #include<iostream> ...

随机推荐

  1. VmProtect v2.12.3 安装注冊

    执行vmprotect.exe開始安装: 1.选择语言.默觉得"English": 2.欢迎页,点"Next"到下一步: 3.授权信息,选"I acc ...

  2. knockoutjs 静动态数据、行为绑定,计算属性及Sync同步更新 Value值更新事件控制

    data-bind="text: firstName"中data-bind属性是Knockout 用来显示关联UI和viewmodel的桥梁, text 表示把绑定的文本赋值给DO ...

  3. 如何判断自己家的宽带是否有公网IP

    1)点击链接 http://www.net.cn/static/customercare/yourIP.asp 抓取自己的IP地址 2)打开一个命令提示符窗口 tracert <刚才获取的IP& ...

  4. 转:sock_ev——linux平台socket事件框架(socket代理类) .

    前面分析了对socket基本操作的封装,并按照数据的传送方式写了两个类,本篇将写一个代理类提供给库的使用者使用的类. /**************************************** ...

  5. Quartz+SpringMVC实现web定时管理任务

    代码地址如下:http://www.demodashi.com/demo/13978.html 使用背景 相信大家在工作过程中,肯定会遇到很多任务定时执行,修改定时任务的时间,执行一次定时任务等等.下 ...

  6. tomcat做成服务

    如果Tomcat是安装版的话服务就已经有了,那么解压版的tomcat(我就经常这么做)没服务怎么办了?     手动把tomcat做成服务方法:      1.环境变量配置jdk      2.运行c ...

  7. C#串口通信程序实现无感知签到与答题

    最近公司项目上线,之前利用串口通讯实现校牌的无感知签到程序, 项目上线以后刚刚好有时间把之前的出现的问题做下记录,废话不多,直接到主题 串口介绍: 串行接口简称串口,也称串行通信接口或串行通讯接口(通 ...

  8. eclipse项目引用项目方法

    在Java Build Path中将被引用项目Add加入到引用项目中. 在Deployment Assembly中将被引入项目Add加到配置项中. 这样在项目发布到tomcat中时被引入项目会被打成j ...

  9. C# 之 FTPserver中文件上传与下载(一)

            近期接手这样一个文件上传到ftpserver的一个功能,接下来就给大家解析一下这一功能. 首先,今天我们要讲的是怎么创建一个FTPserver. 1.首先我们创建一个用户,当然不想创建 ...

  10. TCP 三次握手过程详解

    TCP(Transmission Control Protocol) 传输控制协议 TCP:面向连接的,可靠的,基于字节流的传输层通信协议 TCP(传输层)位于IP层(网络层)之上,应用层之下,不同的 ...