描述

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

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

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

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

  3. 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。 游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。

给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的,但是棋盘上空白的格子的初始位置、指定的可移动的棋子的初始位置和目标位置却可能不同。第 i 次玩的时候,空白的格子在第 EXi行第 EYi 列,指定的可移动棋子的初始位置为第 SXi 行第 SYi 列,目标位置为第 TXi 行第 TYi 列。

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

格式

输入格式

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

接下来的 n 行描述一个 n*m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态,0 表示该格子上的棋子是固定的,1 表示该格子上的棋子可以移动或者该格子是空白的。

接下来的 q 行,每行包含 6 个整数依次是 EXiEYiSXiSYiTXiTYi,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。

输出格式

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

样例1

样例输入1

 
  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

样例输出1

 
  1. 2
  2. -1

限制

每个测试点1s。

提示

样例说明

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

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

    移动过程如下:

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

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

数据范围

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

题解

就是啊,公子还是把这道题过了……【虽然抄了题解的思路但是公子没有抄代码啊】

嗯,用蒟蒻的语言给蒟蒻碰上的人用蒟蒻的方式讲讲吧……

windows画图是神器,嗯。

【1】首先我们需要一个曹操华容道,然后我们观察棋子的性质。

(1)我们可以把移动棋子当做移动白格【显然】

(2)我们只需要关注的是起始棋子【显然】

(3)结合(1)(2)我们需要拿白格子去给起始棋子铺路【显然】

(4)那么如果起始棋子旁边没有白格子时,我们需要把白格子搞到它旁边。【显然】

(5)那么(4)之后我们如果要把起始棋子(在不与上一次移动相反的情况下)向某一方向移动时,我们要把白格子铺在当前棋子位置这一方向【……显然?】

(6)(5)中的操作白格子永远在当前起始棋子位置的四周。【显然?】

【暴搜超时的要点其实是(6),当瞎搞的时候算了很多很多很多遍的让白格子从(x,y)的从上到右,从上到下,从下到左……这样的白格子铺路移动】

(7)那么所有位置可能是放棋子的位置。【显然】

(8)预处理所有位置上下左右四个方向到另外的上下左右四个方向。【………………】

【1】的(4)实现方法:

空白格子对起始格子的四周进行暴搜路径大小。

(9)(8)的方法同上,但暴搜不能经过(x,y)原位置,那就相当于重复移动。

这两个都是非常简单的宽搜。

嗯。我都讲到这个份上了,预处理就可以结束了。

(因为这个图不优美,并不一定是曼哈顿距离。)

【2】我们还需要一个关羽最短路。

(1)为什么需要最短路呢,因为题里说要求最短路【显然】

(2)这张图很工整,可以跑spfa【显然】

(3)上面两句都是废话【……】

(4)我们初始塞进去初始棋子上下左右的四个状态【显然】

(5)我们移动的时候还是需要白格子铺路的代价【显然】

(6)然而我们已经在【1】预处理出来了!【鼓掌】

(7)但是我们发现对于(x,y),从(x-1,y)和(y+1,x)移动来的【诸如此类的】并不一定是一个状态(白格子的方位不同)。【哦QAQ】

(8)但是由于图只有30*30那么大,所以我们多开一维记录方向。【嘿嘿嘿】

(9)然后就变成了一个裸的spfa,带了方向转移即可。【嘿嘿嘿】

【spfa那么简单我拒绝画图。】

题做完了。

代码量↑↑↑……自己写写看吧。

不要抄我的,我写的丑,出门可以转到很多代码优美的神犇那里。

还有我题解写得那么详尽就不要抄了orz。

【不要看↓,这是一个蒟蒻存代码的地方,不要伤害我了QAQ】

  1. #include <iostream>
  2. #include <string.h>
  3. #include <cstdlib>
  4. #include <cstdio>
  5. #include <algorithm>
  6. #include <cstring>
  7. #include <vector>
  8. #include <ctime>
  9. #include <queue>
  10. //#define ivorysi
  11. #define mo 10007
  12. #define siji(i,x,y) for(int i=(x);i<=(y);i++)
  13. #define gongzi(j,x,y) for(int j=(x);j>=(y);j--)
  14. #define xiaosiji(i,x,y) for(int i=(x);i<(y);i++)
  15. #define sigongzi(j,x,y) for(int j=(x);j>(y);j--)
  16. #define ivory(i,x) for(int i=head[x];i;i=edge[i].next)
  17. #define pii pair<int,int>
  18. #define fi first
  19. #define se second
  20. #define inf 0x5f5f5f5f
  21. typedef long long ll;
  22. using namespace std;
  23. struct data{
  24. int x,y,k,step;
  25. };
  26. struct node {
  27. int x,y,k;
  28. };
  29. int dirx[]={,-,,,},diry[]={,,,-,};
  30. int op[]={,,,,};
  31. int n,m,q;
  32. queue<data> q1;
  33. queue<node> q2;
  34. int graph[][],wmove[][][][];
  35. int dist[][][];
  36. bool vis[][][];
  37. bool vis1[][];
  38. int ex,ey,sx,sy,tx,ty;
  39. void pre(int x,int y) {//暴搜处理四周格子部分
  40. siji(i,,) {
  41. if(!graph[x+dirx[i]][y+diry[i]]) continue;
  42. siji(j,,) {
  43. if(i==j || wmove[x][y][i][j]) continue;
  44. int xx=x+dirx[j],yy=y+diry[j];
  45. if(!graph[xx][yy]) continue;
  46. siji(k,,n) siji(l,,m){
  47. vis1[k][l]=;
  48. }
  49. while(!q1.empty()) q1.pop();
  50. q1.push((data){x+dirx[i],y+diry[i],i,});
  51. vis1[x+dirx[i]][y+diry[i]]=;
  52. int ans=-;
  53. while(!q1.empty()) {
  54. data tmp=q1.front();q1.pop();
  55. if(tmp.x==xx && tmp.y==yy) {ans=tmp.step;break;}
  56. siji(l,,) {
  57. if(l!=op[tmp.k]) {
  58. int nx=tmp.x+dirx[l],ny=tmp.y+diry[l];
  59. if((nx!=x || ny!=y ) && graph[nx][ny] &&(!vis1[nx][ny])) {
  60. q1.push((data){nx,ny,l,tmp.step+});
  61. vis1[nx][ny]=;
  62. }
  63. }
  64. }
  65. }
  66. wmove[x][y][i][j]=wmove[x][y][j][i]=ans;
  67. }
  68.  
  69. }
  70. }
  71. void pre_plain() {//处理ex,ey到sx,sy四周的部分
  72. siji(i,,) {
  73. int xx=sx+dirx[i],yy=sy+diry[i];
  74. if(!graph[xx][yy]) continue;
  75. while(!q1.empty()) q1.pop();
  76. int ans=inf;
  77. q1.push((data){ex,ey,,});
  78.  
  79. siji(k,,n) siji(l,,m){
  80. vis1[k][l]=;
  81. }
  82. vis1[ex][ey]=;
  83. while(!q1.empty()) {
  84.  
  85. data tmp=q1.front();q1.pop();
  86. if(tmp.x==xx && tmp.y==yy) {ans=tmp.step;break;}
  87. siji(l,,) {
  88. if(l!=op[tmp.k]) {
  89. int nx=tmp.x+dirx[l],ny=tmp.y+diry[l];
  90. if((nx!=sx || ny!=sy) && graph[nx][ny] && (!vis1[nx][ny])) {
  91. q1.push((data){nx,ny,l,tmp.step+});
  92. vis1[nx][ny]=;
  93. }
  94. }
  95. }
  96. }
  97. if(ans<inf) {//顺手把状态塞进去
  98. dist[xx][yy][i]=ans+;
  99. vis[xx][yy][i]=;
  100. q2.push((node){xx,yy,i});
  101. }
  102. }
  103. }
  104. void solve() {
  105. while(!q2.empty()) q2.pop();
  106. siji(i,,n) siji(j,,m) siji(l,,){
  107. dist[i][j][l]=inf;
  108. vis[i][j][l]=;
  109. }
  110. pre_plain();
  111. int ans=inf;
  112. if(tx==sx && ty==sy) ans=;//不知道这个特判有没有用
  113. while(!q2.empty()) {
  114. node tmp=q2.front();q2.pop();vis[tmp.x][tmp.y][tmp.k]=;
  115. if(tmp.x==tx && tmp.y==ty) {//搜到了就停
  116. ans=min(ans,dist[tmp.x][tmp.y][tmp.k]);
  117. continue;
  118. }
  119. siji(i,,) {
  120. if(i!=op[tmp.k]) {
  121. int nx=tmp.x+dirx[i],ny=tmp.y+diry[i];
  122. if(!graph[nx][ny]) continue;
  123. int val=wmove[tmp.x][tmp.y][op[tmp.k]][i];
  124. if(val<=) continue;//此时说明这个方向格子走不动
  125. if(dist[nx][ny][i]>dist[tmp.x][tmp.y][tmp.k]+val+){
  126. dist[nx][ny][i]=dist[tmp.x][tmp.y][tmp.k]+val+;
  127. if(!vis[nx][ny][i]) {
  128. vis[nx][ny][i]=;
  129. q2.push((node){nx,ny,i});
  130. }
  131. }
  132. }
  133. }
  134. }
  135. if(ans>=inf || ans<) ans=-;
  136. printf("%d\n",ans);
  137. }
  138. void Main() {
  139. scanf("%d%d%d",&n,&m,&q);
  140. siji(i,,n) {
  141. siji(j,,m) {
  142. scanf("%d",&graph[i][j]);
  143. }
  144. }
  145. siji(i,,n) {
  146. siji(j,,m) {
  147. if(graph[i][j]) pre(i,j);
  148. }
  149. }
  150. siji(i,,q) {
  151. scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
  152. solve();
  153. }
  154. }
  155. int main() {
  156. Main();
  157. }

华容道

noip2013Day2T3-华容道【一个蒟蒻的详细题解】的更多相关文章

  1. 【一个蒟蒻的挣扎】最小生成树—Kruskal算法

    济南集训第五天的东西,这篇可能有点讲不明白提前抱歉(我把笔记忘到别的地方了 最小生成树 概念:一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的 ...

  2. 一个蒟蒻对FFT的理解(蒟蒻也能看懂的FFT)

    建议同学们先自学一下"复数(虚数)"的性质.运算等知识,不然看这篇文章有很大概率看不懂. 前言 作为一个典型的蒟蒻,别人的博客都看不懂,只好自己写一篇了. 膜拜机房大佬 HY 一. ...

  3. 这是一个蒟蒻的计划……QAQ

    感觉像我这种拖拉的人很有可能是完成不了的,挂上来相当于监督我自己啦QWQ [学习计划] [√]1.去看Trie树!!!   yyb学长的blog 2.KMP还有AC自动机 先贴两个链接在这里吧:KMP ...

  4. 一个蒟蒻的解题过程记录——洛谷P1003 铺地毯

    这到题算是我“火线回归”后码的第一道题,病好了心情不错,发篇博客分享一下 目录: ·题目描述 ·题目分析 ·解题思路 ·代码实现 ·总结 ·题目描述: 为了准备一场特殊的颁奖典礼,组织者在会场的一片矩 ...

  5. 【一个蒟蒻的挣扎】LCA (倍增)

    #include<cstdio> #include<iostream> #include<cstring> using namespace std; struct ...

  6. 论一个蒟蒻的脑子里可以有多少坑(貌似咕了……目前更新保持在noip阶段)

    就是错题整理了,其实也会把一些不该犯的失误整进来. 其实之前一直拖着不想写,直到某次模拟赛,看错了2道题,顺便爆了一道题的int(没错第一个点就会爆)之后爆零了,吓得我赶紧把这篇博客搞出来了..... ...

  7. 【一个蒟蒻的挣扎】单源最短路(Dijkstra)

    赛前没啥时间好好解释了,还有三天2019CSP,大家加油啊!!! ヾ(◍°∇°◍)ノ゙ 背掉它就好啦!!! 我觉得我这一版打得还行就放上来了 #include<cstdio> #inclu ...

  8. 蒟蒻kc的垃圾数列

    题目背景 在某教练的强迫之下,我一个蒟蒻居然出题了!!!出题了!!!(数据太水别找我qwq) 好的,JL说好的一题100快拿来 题目描述 首先,给你一个空的长度为n的序列(废话) 然后,你有一系列神奇 ...

  9. USACO 简易题解(蒟蒻的题解)

    蒟蒻难得可以去比赛,GDOI也快到了,还是认真刷题(不会告诉你之前都在颓废),KPM 神犇既然都推荐刷USACO, 辣就刷刷. 现在蒟蒻还没刷完,太蒟刷得太慢,so 写了的搞个简易题解(没代码,反正N ...

随机推荐

  1. 算法笔记_015:快速排序(Java)

    目录 1 问题描述 2 解决方案 2.1 快速排序原理简介 2.2 具体编码 1 问题描述 给定一组数据,使用快速排序得到这组数据的非降序排列. 2 解决方案 2.1 快速排序原理简介 引用自百度百科 ...

  2. (四)python自带解释器(LDIE)的使用

    什么是IDE? Integrated Development Environment(集成开发环境) 打个不恰当的比方,如果说写代码是制作一件工艺品,那IDE就是机床.再打个不恰当的比方,PS就是图片 ...

  3. Python高手之路【十】python基础之反射

    反射说简单点 --> 就是利用字符串的形式去对象(模块)中操作(寻找/检查/删除/设置)成员. 需求:由用户输入一个模块名,用户输入什么模块名,文件中就导入什么模块: 1:文件都在同一目录下的导 ...

  4. learning english

    distortion 英[dɪ'stɔ:ʃn] 美[dɪˈstɔrʃən]n. 扭曲,变形; 失真,畸变; [心理学] 扭转;[例句]I think it would be a gross disto ...

  5. 移动端-H5预加载页面

    利用简洁的图片预加载组件提升h5移动页面的用户体验   阅读目录 1. 实现思路 2. demo说明 3. 注意事项 4. 总结 在 做h5移动页面,相信大家一定碰到过页面已经打开,但是里面的图片还未 ...

  6. PopupWindow 的使用

    //contentView : 气泡显示的内容 //width ,height : 宽高 PopupWindow popupWindow = new PopupWindow(contentView, ...

  7. 使用pycharm+pyqt5 触发自定义方法

    1.依旧使用上次QtDesigner做的界面,如下图: 2.本次的使用text Browser 和 text Edit 和 pushButton控件做触发联系: 3.目的实现在text Edit中随意 ...

  8. json字符串中key值下划线命名转换为驼峰命名

    json字符串中key值下划线命名转换为驼峰命名: 例如: 原json串: String json= "{'user_name':'ok','user_sex':0,'object_info ...

  9. mmmmmmmm

    // // AView.m // AutoLayout // // Created by ZhuYi on 16/5/24. // Copyright © 2016年 ZY. All rights r ...

  10. scale-free network

    原文链接:http://lihailian.bokee.com/6013647.html 1.什么是无尺度现象? 统计物理学家习惯于把服从幂次分布的现象称为无尺度现象. 在做大量统计实验之前,科学家预 ...