习题:八数码难题(双向BFS)
八数码难题(wikioi1225)
【题目描述】
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
【输入描述】
输入初试状态,一行九个数字,空格用0表示。
【输出描述】
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)。
【样例输入 】
283104765
【样例输出】
4
分析:
很经典题目,题意不解释了。
看到最小步骤会想到广搜,本题可以看成是空格移动达到目标状态的问题,记录空格位置和棋盘状态,加入队列不断增加节点入队。同时注意判重,将棋盘转换为九位数(如果第一个数字为0则是八位数),用hash表解决。这样就可以过这道题了。
但是为了达到更好的时间效率,可以使用双向广搜。
双向宽搜,顾名思义就是从两边搜,适用于已知起始状态和目标状态,求最短步骤的题目。
我们可以开两类数组,分别表示正方方向搜索的队列,然后初始,目标状态分别入对应队列,进行扩展节点,直到两个方向搜索相遇时即得出最短步骤。
出于优化时间的目的,我们往往先搜队列中节点少的方向,轮流进行。
具体讲就是:两个方向根据队列中节点数交替扩展节点,每扩展一个节点为,在本队列判重后还要在另一个方向的队列中找是否出现,出现说明相遇,输出最短步骤为正方方向扩展到该节点所需最短步骤。
注意双向广搜时,反方向扩展节点时操作与正方向相反,比如向左移动要变为向右移动,但这点对本题没有影响。
解释一下
head,tail表示队头队尾指针,v表示最短步骤,w是棋盘状态,px,py表示空格位置。
0表示正方向,1表示反方向。彼此可用1-x转换。
以下就是自己写的了双向广搜+hash判重的八数码AC程序。
代码
program puzzle;
const
maxn=;
type
hh=^node;
node=record
data:longint;
text:longint;
next:hh;
end;
var
dx:array[..]of longint=(,,,-);
dy:array[..]of longint=(,-,,);
hash:array[..,..maxn]of hh;
head,tail:array[..]of longint;
w:array[..,..,..,..]of longint;
b:array[..,..]of longint;
px,py,v:array[..,..]of longint;
n,i,m,j,x,y,s,h,t,k,r:longint;
c:char;
function haha(t,x:longint):boolean;
var i,j,xx:longint;p:hh;
begin
xx:=x mod maxn;
new(p);
p:=hash[t,xx];
while p<>nil do
begin
if p^.data=x then begin r:=p^.text; exit(true); end;
p:=p^.next;
end;
exit(false);
end;
procedure put(t,x:longint);
var q:hh;xx:longint;
begin
xx:=x mod maxn;
new(q);
q^.data:=x; q^.text:=tail[t]; q^.next:=hash[t,xx];
hash[t,xx]:=q;
end;
procedure bfs(x:longint);
var i,j,u,l,ans,xx,yy,g,tmp:longint;
begin
head[x]:=head[x]+;
for i:= to do
begin b:=w[x,head[x]];
xx:=px[x,head[x]]+dx[i]; yy:=py[x,head[x]]+dy[i];
tmp:=b[xx,yy];
b[xx,yy]:=b[px[x,head[x]],py[x,head[x]]];
b[px[x,head[x]],py[x,head[x]]]:=tmp;
g:=; ans:=;
for u:= to do begin
for l:= to do
begin ans:=ans+g*b[u,l]; g:=g div ; end;
end;
if (xx>)and(xx<=)and(yy>)and(yy<=)and(haha(x,ans)=false) then
begin
tail[x]:=tail[x]+; px[x,tail[x]]:=xx; py[x,tail[x]]:=yy;
w[x,tail[x]]:=b; v[x,tail[x]]:=v[x,head[x]]+; put(x,ans);
if haha(-x,ans)=true then
begin
writeln(v[x,tail[x]]+v[-x,r]); k:=; break;
end;//在另一个方向的队列中查找该节点
end;
if k= then break;
end;
if k= then exit;
end;
begin
t:=;
for i:= to do begin
for j:= to do
begin read(c);if c='' then begin x:=i; y:=j;end;
w[,,i,j]:=ord(c)-; s:=s+w[,,i,j]*t; t:=t div ; end;
end;
put(,); put(,s); k:=;//存入两个hash数组
w[,,,]:=; w[,,,]:=; w[,,,]:=;
w[,,,]:=; w[,,,]:=; w[,,,]:=;
w[,,,]:=; w[,,,]:=; w[,,,]:=;
v[,]:=; v[,]:=; px[,]:=; py[,]:=; px[,]:=x; py[,]:=y;
head[]:=; head[]:=; tail[]:=; tail[]:=;
repeat
if (tail[]>head[])and((tail[]-head[]<tail[]-head[])or(tail[]<=head[]))
then bfs()
else if tail[]>head[] then bfs();//交替扩展节点
if k= then break;
until ((head[]>=tail[])or(tail[]>=))and((head[]>=tail[])or(tail[]>=));
end.
使用双向广搜,时间效率大大提高,两种方法在不加其它优化的时间效率对比
广搜+hash
双向广搜+hash
习题:八数码难题(双向BFS)的更多相关文章
- 【洛谷】P1379 八数码难题(bfs)
题目 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局 ...
- HDOJ-1043 Eight(八数码问题+双向bfs+高效记录路径+康拓展开)
bfs搜索加记录路径 HDOJ-1043 主要思路就是使用双向广度优先搜索,找最短路径.然后记录路径,找到结果是打印出来. 使用康拓序列来来实现状态的映射. 打印路径推荐使用vector最后需要使用a ...
- 八数码问题 双向BFS/Hsh链表存储
转自洛谷 作者EndSaH #include<iostream> #include<string> #include<cmath> #include<cstr ...
- cdoj 414 八数码 (双向bfs+康拓展开,A*)
一道关乎人生完整的问题. DBFS的优越:避免了结点膨胀太多. 假设一个状态结点可以扩展m个子结点,为了简单起见,假设每个结点的扩展都是相互独立的. 分析:起始状态结点数为1,每加深一层,结点数An ...
- 洛谷——P1379 八数码难题
P1379 八数码难题 双向BFS 原来双向BFS是这样的:终止状态与起始状态同时入队,进行搜索,只不过状态标记不一样而已,本题状态使用map来存储 #include<iostream> ...
- 双向广搜+hash+康托展开 codevs 1225 八数码难题
codevs 1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Yours和zero在研究A*启 ...
- Codevs 1225 八数码难题
1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Yours和zero在研究A*启发式算法.拿到一道经典的 ...
- [luogu]P1379 八数码难题[广度优先搜索]
八数码难题 ——!x^n+y^n=z^n 我在此只说明此题的一种用BFS的方法,因为本人也是初学,勉勉强强写了一个单向的BFS,据说最快的是IDA*(然而蒟蒻我不会…) 各位如果想用IDA*的可以看看 ...
- 洛谷P1379八数码难题
题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中. 要求解的问题是:给出一种初始布局(初始状态)和目标布局(为 ...
随机推荐
- iOS中的崩溃类型
http://blog.csdn.net/womendeaiwoming/article/details/44243571 OS中的崩溃类型 在这里了解一下XCode用来表示各种崩溃类型的术语,补充一 ...
- 【洛谷3796】【模板】AC自动机(加强版)
点此看题面 大致题意: 一道模板题,给你\(N\)个模式串和一个文本串,要你求出在文本串中出现次数最多的若干个模式串并输出它们. \(AC\)自动机 都说了是\(AC\)自动机的模板题,做法肯定是\( ...
- Solaris&&QNX® Neutrino®&&OpenVMS&&FreeBSD&&AIX
原文链接Solaris (读作 /se'laris:/ 或者 /so'le:ris/ 或者 '梭拉瑞斯' )是Sun Microsystems研发的计算机 操作系统.它被认为是UNIX操作系统的衍生版 ...
- maven手动导入jar包到本地仓库
一.cmd进入maven的bin目录下(我的目录是E:\cloud_cms\apache-maven-3.5.4\bin) cd E:\cloud_cms\apache-maven-3.5.4\bin ...
- Android驱动开发5-7总结
Android深度探索5-7章总结 介绍了S3C6410开发板的功能,开发板的不同主要是在烧录嵌入式系统的方式不同,以及如何在此开发板上安装Android.紧接着学到介绍到如何在多种平台,使用多种方式 ...
- 网络流_spfa最小费用最大流
最大流: 不断搜索增广路,寻找最小的容量-流量,得到最大流量,但最大流量在有花费时不一定是最小花费. 最小费用最大流 算法思想: 采用贪心的思想,每次找到一条从源点到达汇点的花费最小的路径,增加流量, ...
- git bash学习3 -简单杂乱知识点记录
branch 新建分支 git init git add git commit 先新建一个仓库以及master 然后新建分支 git branch BranchName 然后切换分支 git chec ...
- eclipse projectExplorer视图(以包的方式显示)与navigator视图切换(以文件夹的方式显示)及树状视图与平面视图的切换
projectExplorer与navigator的切换 projectExplorer视图效果 想要此视图效果步骤如下: 分割------------------------------------ ...
- 等比例适配所有屏幕---css3 rem用法
1,rem的定义 rem(font size of the root element)是指相对于根元素的字体大小的单位.rem是一个相对单位.和em非常相似.em(font size of the e ...
- 精简Docker镜像的五种通用方法
http://dockone.io/article/8163 精简Docker镜像的好处很多,不仅可以节省存储空间和带宽,还能减少安全隐患.优化镜像大小的手段多种多样,因服务所使用的基础开发语言不同而 ...