Describltion

小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时间。

小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:

  1. 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的;

  2. 有些棋子是固定的,有些棋子则是可以移动的;

  3. 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。

游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。

给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的, 但是棋盘上空白的格子的初始位置、 指定的可移动的棋子的初始位置和目标位置却可能不同。第 i 次

玩的时候, 空白的格子在第 EXi 行第 EYi 列,指定的可移动棋子的初始位置为第 SXi 行第 SYi列,目标位置为第 TXi 行第 TYi 列。

假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。

Input

输入文件为 puzzle.in。

第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n、m 和 q;

接下来的 n 行描述一个 n*m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态,0 表示该格子上的棋子是固定的,1 表示该格子上的棋子可以移动或者该格子是空白的。接下来的 q 行,每行包含 6 个整数依次是 EXi、EYi、SXi、SYi、TXi、TYi,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。

Output

输出文件名为 puzzle.out。

输出有 q 行,每行包含 1 个整数,表示每次游戏所需要的最少时间,如果某次游戏无法完成目标则输出−1。

Sample Input

  1. 3 4 2
  2. 0 1 1 1
  3. 0 1 1 0
  4. 0 1 0 0
  5. 3 2 1 2 2 2
  6. 1 2 2 2 3 2
Sample Output

  1. 2
  2. -1

Explanation

棋盘上划叉的格子是固定的,红色格子是目标位置,圆圈表示棋子,其中绿色圆圈表示目标棋子。

  1. 第一次游戏,空白格子的初始位置是 (3, 2)(图中空白所示),游戏的目标是将初始位置在(1, 2)上的棋子(图中绿色圆圈所代表的棋子)移动到目标位置(2, 2)(图中红色的格子)上。

移动过程如下:

  1. 第二次游戏,空白格子的初始位置是(1, 2)(图中空白所示),游戏的目标是将初始位置在(2, 2)上的棋子(图中绿色圆圈所示)移动到目标位置 (3, 2)上。

要将指定块移入目标位置,必须先将空白块移入目标位置,空白块要移动到目标位置,必然是从位置(2, 2)上与当前图中目标位置上的棋子交换位置,之后能与空白块交换位置的只有当前图中目标位置上的那个棋子,因此目标棋子永远无法走到它的目标位置, 游戏无法完成。

Data Range

对于 30%的数据,1 ≤ n, m ≤ 10,q = 1;

对于 60%的数据,1 ≤ n, m ≤ 30,q ≤ 10;

对于 100%的数据,1 ≤ n, m ≤ 30,q ≤ 500。

Solution

首先观察一下这道题,我们可以看出

  1.不同棋子的移动,可以看成唯一的空格在移动

  2.一个棋子要移动,旁边必须存在空格

所以我们可以知道,目标棋子要从起点开始移动,空格必须先移到它旁边。

然后目标棋子可以开始走了,但它走必须也要带着空格跑

所以记录状态的时候,必须把三个状态都记录下来,直到它到终点。

所以我们可以看出此题分为两个步骤:

1.空格移到目标棋子身旁

2.目标棋子带着空格从起点到终点

考虑一下搜索的复杂度限制,Q<=500,那么搜索的要限制在10w以内

显然第一遍是二维状态,一次bfs即可搞定,复杂度不超过n2

而第二遍有四个维度直接搞可能会T,所以要思考如何优化。

我们发现,空格只有4种有效走法:从某一个位置移到目标棋子相邻的其他三个格子上且不经过目标棋子,或者与目标棋子交换位置。

所以对应每一种状态之间的转换我们可以用一条边相连,最后跑一次从起点到终点的SPFA就行了。

这里记录状态有个小技巧,记录两个点,我们可以把它压缩一下 ,记录目标棋子的坐标,并用加上t=0,1,2,3分别代表空格在哪个方向,最后某一个状态的编号就可以表示成120x+4y+i

代码

  1. #include<set>
  2. #include<map>
  3. #include<stack>
  4. #include<queue>
  5. #include<cstdio>
  6. #include<cstring>
  7. #include<iostream>
  8. #include<algorithm>
  9. #define RG register int
  10. #define rep(i,a,b) for(RG i=a;i<=b;i++)
  11. #define per(i,a,b) for(RG i=a;i>=b;i--)
  12. #define ll long long
  13. #define inf (1<<30)
  14. #define maxn 35
  15. #define maxm 38888
  16. using namespace std;
  17. int n,m,q,cnt;
  18. int vis[maxm],dis[maxn][maxn],gra[maxn][maxn],d[maxm],head[maxm];
  19. struct E{
  20. int v,next,val;
  21. }edge[maxm];
  22. struct P{
  23. int x,y;
  24. P operator + (const P &tmp)const{
  25. return (P){x+tmp.x,y+tmp.y};
  26. }
  27. }dir[];
  28. inline int read()
  29. {
  30. int x=,f=;char c=getchar();
  31. while(c<''||c>''){if(c=='-')f=-;c=getchar();}
  32. while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
  33. return x*f;
  34. }
  35.  
  36. inline int check(P tmp)
  37. {
  38. if(!gra[tmp.x][tmp.y]||dis[tmp.x][tmp.y]) return ;return ;
  39. }
  40.  
  41. inline void add(int u,int v,int val)
  42. {
  43. edge[++cnt].v=v,edge[cnt].val=val,edge[cnt].next=head[u],head[u]=cnt;
  44. }
  45.  
  46. void bfs(int sx,int sy,int tx,int ty,int type)
  47. {
  48. memset(dis,,sizeof(dis));dis[sx][sy]=;
  49. queue<P> que;que.push((P){sx,sy});
  50. P u,v;
  51. while(!que.empty())
  52. {
  53. u=que.front(),que.pop();
  54. rep(i,,)
  55. {
  56. v=u+dir[i];
  57. if(!check(v)) continue;
  58. if(v.x==tx&&v.y==ty) continue;
  59. dis[v.x][v.y]=dis[u.x][u.y]+;que.push((P){v.x,v.y});
  60. }
  61. }
  62. if(type==) return;
  63. u=(P){tx,ty};
  64. rep(i,,)
  65. {
  66. v=u+dir[i];
  67. if(v.x==sx&&v.y==sy) continue;
  68. if(!dis[v.x][v.y]) continue;
  69. add(tx*+ty*+type,tx*+ty*+i,dis[v.x][v.y]-);
  70. }
  71. add(tx*+ty*+type,sx*+sy*+type^,);
  72. }
  73.  
  74. void spfa(int sx,int sy)
  75. {
  76. P u=(P){sx,sy},v;int vid;
  77. queue<int> qe;
  78. rep(i,,) d[i]=inf,vis[i]=;
  79. rep(i,,)
  80. {
  81. v=u+dir[i];vid=sx*+sy*+i;
  82. if(dis[v.x][v.y]) qe.push(vid),d[vid]=dis[v.x][v.y]-,vis[vid]=;
  83. }
  84. while(!qe.empty())
  85. {
  86. int x=qe.front();qe.pop();vis[x]=;
  87. for(int i=head[x];i;i=edge[i].next)
  88. {
  89. int y=edge[i].v,w=edge[i].val;
  90. if(d[y]>d[x]+w)
  91. {
  92. d[y]=d[x]+w;
  93. if(!vis[y]) qe.push(y),vis[y]=;
  94. }
  95. }
  96. }
  97. }
  98.  
  99. void init()
  100. {
  101. dir[]=(P){-,};dir[]=(P){,};dir[]=(P){,-};dir[]=(P){,};
  102. rep(i,,n)
  103. rep(j,,m)
  104. {
  105. if(!gra[i][j]) continue;
  106. if(gra[i-][j]) bfs(i-,j,i,j,);
  107. if(gra[i+][j]) bfs(i+,j,i,j,);
  108. if(gra[i][j-]) bfs(i,j-,i,j,);
  109. if(gra[i][j+]) bfs(i,j+,i,j,);
  110. }
  111.  
  112. rep(i,,q)
  113. {
  114. int ax=read(),ay=read(),bx=read(),by=read(),cx=read(),cy=read();
  115. if(bx==cx&&by==cy){puts("");continue;}
  116. bfs(ax,ay,bx,by,);
  117. spfa(bx,by);
  118. int ans=inf;
  119. rep(j,,) ans=min(ans,d[cx*+cy*+j]);
  120. if(ans==inf) puts("-1");
  121. else printf("%d\n",ans);
  122.  
  123. }
  124. }
  125.  
  126. int main()
  127. {
  128. n=read(),m=read(),q=read();
  129. rep(i,,n) rep(j,,m) gra[i][j]=read();
  130. init();
  131. return ;
  132. }

题外话

在做这道题debug的时候,发现了一些莫名其妙的错误:在给vis[]数组清零之后,原本的head[]发生了改变?花了我一个小时的时间,终于发现了,我定义的大小比我用循环清零的次数要小!我以为我见鬼了,两个毫不相关的数组产生了干扰。应该是越界了清零到另一个数组去了,以后一定要小心这种错误!

华容道 [NOIP 2013]的更多相关文章

  1. Luogu 1979 NOIP 2013 华容道(搜索,最短路径)

    Luogu 1979 NOIP 2013 华容道(搜索,最短路径) Description 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面 ...

  2. NOIP 2013 货车运输【Kruskal + 树链剖分 + 线段树 】【倍增】

    NOIP 2013 货车运输[树链剖分] 树链剖分 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在 ...

  3. [Noip 2013 Day1-3] 货车运输 做法总结

    [Noip 2013 Day1-3] 货车运输 做法总结 Online Judge:Luogu-1967 Label:启发式合并,离线,整体二分,按秩合并,倍增,最大生成树 打模拟离线赛时做到,顺便总 ...

  4. 【CodeVS 3290】【NOIP 2013】华容道

    http://codevs.cn/problem/3290/ 据说2013年的noip非常难,但Purpleslz学长还是AK了.能A掉这道题真心orz. 设状态$(i,j,k)$表示目标棋子在$(i ...

  5. 【NOIP 2013 DAY2 T3】 华容道(spfa)

    题目描述 [问题描述] 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时间. 小 ...

  6. noip 2013 华容道

    /*双向bfs (得分和单项的一样多....)70*/ #include<iostream> #include<cstdio> #include<cstring> ...

  7. 洛谷 P1979 [ NOIP 2013 ] 华容道 —— bfs + 最短路

    题目:https://www.luogu.org/problemnew/show/P1979 真是一道好题... 首先考虑暴力做法,应该是设 f[i][j][x][y] 记录指定棋子和空格的位置,然后 ...

  8. NOIP 2013

    Prob.1 转圈游戏 找到循环节,然后快速幂.代码: #include<cstdio> #include<cstring> #include<iostream> ...

  9. NOIP 2013 day2

    tags: 模拟 贪心 搜索 动态规划 categories: 信息学竞赛 总结 积木大赛 花匠 华容道 积木大赛 Solution 发现如果一段先单调上升然后在单调下降, 那么这一块的代价是最高的减 ...

随机推荐

  1. CA认证的原理和流程及https原理

    1.什么是CA证书. 看过一些博客,写的比较形象具体. ◇ 普通的介绍信 想必大伙儿都听说过介绍信的例子吧?假设 A 公司的张三先生要到 B 公司去拜访,但是 B 公司的所有人都不认识他,他咋办捏?常 ...

  2. 浅拷贝和深拷贝(谈谈java中的clone)

    clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象.所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象.那么在java语言中,有 ...

  3. SpringBoot整合Kafka

    一.准备工作 提前启动zk,kafka,并且创建一个Topic("Hello-Kafk") bin/kafka-topics.sh --create --zookeeper 192 ...

  4. phoenix表操作

    phoenix表操作 进入命令行,这是sqlline.py 配置到path环境变量的情况下 sqlline.py localhost如果要退出命令行:!q 或者 !quit 3.4.1     创建表 ...

  5. Visual Studio "14" CTPs

    下载地址:http://www.visualstudio.com/en-us/downloads/visual-studio-14-ctp-vs       上张有亮点的图: 实现亮点的方法(Remo ...

  6. POJ 2987 Firing【最大权闭合图-最小割】

    题意:给出一个有向图,选择一个点,则要选择它的可以到达的所有节点.选择每个点有各自的利益或损失.求最大化的利益,以及此时选择人数的最小值. 算法:构造源点s汇点t,从s到每个正数点建边,容量为利益.每 ...

  7. 开源工具软件XMusicDownloader——音乐下载神器

    XMusicDownloader,一款 支持从百度.网易.qq和酷狗等音乐网站搜索并下载歌曲的程序. 缘起: 一直用网易音乐听歌,但是诸如李健.周杰伦的不少歌曲,网易都没有版权,要从QQ等音乐去下载, ...

  8. C语言关于进制转换,补码, 整数的位操作

    菜单导航: 1.二进制.八进制.十进制.十六进制的相互转换 2.原码.反码.补码 3.举例证明整数在计算机内是以补码的形式存在(以负数为例) 4.整数的位操作:按位且&.或|.异或^.取反~ ...

  9. 搜狐JS查ip

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. Tomcat中文乱码解决办法

    有时候发现自己将中文编码后还是会存在乱码的情况,解决办法就是在Server.xml中的Connector结点,配置 URIEncoding="UTF-8"即可