八数码难题(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)的更多相关文章

  1. 【洛谷】P1379 八数码难题(bfs)

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

  2. HDOJ-1043 Eight(八数码问题+双向bfs+高效记录路径+康拓展开)

    bfs搜索加记录路径 HDOJ-1043 主要思路就是使用双向广度优先搜索,找最短路径.然后记录路径,找到结果是打印出来. 使用康拓序列来来实现状态的映射. 打印路径推荐使用vector最后需要使用a ...

  3. 八数码问题 双向BFS/Hsh链表存储

    转自洛谷 作者EndSaH #include<iostream> #include<string> #include<cmath> #include<cstr ...

  4. cdoj 414 八数码 (双向bfs+康拓展开,A*)

    一道关乎人生完整的问题. DBFS的优越:避免了结点膨胀太多. 假设一个状态结点可以扩展m个子结点,为了简单起见,假设每个结点的扩展都是相互独立的. 分析:起始状态结点数为1,每加深一层,结点数An ...

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

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

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

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

  7. Codevs 1225 八数码难题

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

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

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

  9. 洛谷P1379八数码难题

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

随机推荐

  1. POJ 1065 Wooden Sticks(LIS,最少链划分)

    题意:求二维偏序的最少链划分. 用到Dilworth定理:最少链划分=最长反链.(对偶也成立,个人认为区别只是一个维度上的两个方向,写了个简单的证明 相关概念:偏序集,链,反链等等概念可以参考这里:h ...

  2. Android(java)学习笔记98:如何让你的GridView不再滚动

    1. 如何让你的GridView不再滚动: GridView显示不完整的原因是因为,他的外层也套用了一个滑动的控件,这个解决办法是:重写GridView,是控制GridView不能滚动,就是写一个类继 ...

  3. 第六十三课、C语言的异常处理

    http://www.cnblogs.com/gui-lin/p/6379101.html 一.异常处理 1.异常的概念 (1).程序在运行过程中可能产生异常 (2).异常(Exception)和Bu ...

  4. 常量池与方法区以及又读new String对象创建问题

    又拿出这道String str1 = new String("abc");创建几个对象的面试题梳理了一下常量池与方法区的关系,希望能把这两者的关系通过这道面试题说明白 方法区是什么 ...

  5. Java代码工具箱之超出游标最大数

    1. Java大量写入oracle时容易出现此错.经过此错,也触动自己要深刻理解 java 的 prepareStatement 等对象,及数据库的连接与释放. 2. 原因:经常会出现在 for 循环 ...

  6. C#事件与接口编程实例

    很多初学c#的朋友对于事件与接口感到迷惑不解,不明白它们之间的关系,下面我就用实例来简单的分析讲解一下. 事件,用event修饰符来代表一个事件,我们要创建一个C#事件必须按以下顺序来扫行: 1,创建 ...

  7. 统计学基于SPSS贾俊平 授课笔记 发布作业 spss19cn 软件下载地址及破解包spss19_10039 下载地址

    spss19cn软件下载地址及破解包spss19_10039 软件包下载地址一 http://www.33lc.com/soft/41991.html 软件包下载地址二 http://dl.pconl ...

  8. Vue中结合clipboard实现复制功能

    首先现在Vue中引入clipboard npm install clipboard --save 在需要使用的组件中import 引入clipboard import Clipboard from ' ...

  9. [JZOJ] 5935. 小凯学数学

    由Noip2018初赛的知识得,a|b + a&b = a+b 设计一个区间dp,设\(f[l][r][x]\)表示区间\([l,r]\)能否构成\(x\),数据不大,转移暴力枚举 复杂度\( ...

  10. mysql 查询 7天内的数据

    SELECT ID,SERVICE FROM new_schedules_spider_full WHERE SERVICE = 'WSA2' and date_sub(curdate(), inte ...