noip2013Day2T3-华容道【一个蒟蒻的详细题解】

描述

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

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

  1. 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的;
  2. 有些棋子是固定的,有些棋子则是可以移动的;
  3. 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。 游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。

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

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

格式

输入格式

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

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

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

输出格式

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

样例1

样例输入1

3 4 2
0 1 1 1
0 1 1 0
0 1 0 0
3 2 1 2 2 2
1 2 2 2 3 2

样例输出1

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[5]={0,-1,1,0,0},diry[5]={0,0,0,-1,1};
 30 int op[5]={0,2,1,4,3};
 31 int n,m,q;
 32 queue<data> q1;
 33 queue<node> q2;
 34 int graph[35][35],wmove[35][35][5][5];
 35 int dist[35][35][4];
 36 bool vis[35][35][4];
 37 bool vis1[35][35];
 38 int ex,ey,sx,sy,tx,ty;
 39 void pre(int x,int y) {//暴搜处理四周格子部分
 40     siji(i,1,4) {
 41         if(!graph[x+dirx[i]][y+diry[i]]) continue;
 42         siji(j,1,4) {
 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,1,n) siji(l,1,m){
 47                 vis1[k][l]=0;
 48             }
 49             while(!q1.empty()) q1.pop();
 50             q1.push((data){x+dirx[i],y+diry[i],i,0});
 51             vis1[x+dirx[i]][y+diry[i]]=1;
 52             int ans=-1;
 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,1,4) {
 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+1});
 61                             vis1[nx][ny]=1;
 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,1,4) {
 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,0,0});
 78
 79         siji(k,1,n) siji(l,1,m){
 80             vis1[k][l]=0;
 81         }
 82         vis1[ex][ey]=1;
 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,1,4) {
 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+1});
 92                         vis1[nx][ny]=1;
 93                     }
 94                 }
 95             }
 96         }
 97         if(ans<inf) {//顺手把状态塞进去
 98             dist[xx][yy][i]=ans+1;
 99             vis[xx][yy][i]=1;
100             q2.push((node){xx,yy,i});
101         }
102     }
103 }
104 void solve() {
105     while(!q2.empty()) q2.pop();
106     siji(i,1,n) siji(j,1,m) siji(l,1,4){
107         dist[i][j][l]=inf;
108         vis[i][j][l]=0;
109     }
110     pre_plain();
111     int ans=inf;
112     if(tx==sx && ty==sy) ans=0;//不知道这个特判有没有用
113     while(!q2.empty()) {
114         node tmp=q2.front();q2.pop();vis[tmp.x][tmp.y][tmp.k]=0;
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,1,4) {
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<=0) continue;//此时说明这个方向格子走不动
125                 if(dist[nx][ny][i]>dist[tmp.x][tmp.y][tmp.k]+val+1){
126                     dist[nx][ny][i]=dist[tmp.x][tmp.y][tmp.k]+val+1;
127                     if(!vis[nx][ny][i]) {
128                         vis[nx][ny][i]=1;
129                         q2.push((node){nx,ny,i});
130                     }
131                 }
132             }
133         }
134     }
135     if(ans>=inf || ans<0) ans=-1;
136     printf("%d\n",ans);
137 }
138 void Main() {
139     scanf("%d%d%d",&n,&m,&q);
140     siji(i,1,n) {
141         siji(j,1,m) {
142             scanf("%d",&graph[i][j]);
143         }
144     }
145     siji(i,1,n) {
146         siji(j,1,m) {
147             if(graph[i][j]) pre(i,j);
148         }
149     }
150     siji(i,1,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 }

华容道

时间: 2024-11-25 11:55:37

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

记一个蒟蒻的绝望

感觉现在…… 怎么讲,心挺冷的. 今天一月五号了.距离省选,时间好短啊. 我还有那么多东西不懂.甚至听都没听说过. 等到真正去省选的时候,我可能跟现在一样,什么都不会. 我的名字能不能被看到都不知道.哈,还进队呢. …… 我NOIP似乎考的很好.然而首先我只有24名,其次我实力到不了420. 我D2T2打的是状压贪心.rqy和gc回来的路上告诉我,我那个DP,显而易见是没有考虑周全的. 所以我实力大概是320分.320分,能做得了什么? …… zht说自己现在省选没可能的.四月差不多可以. 我四

【一个蒟蒻的挣扎】模拟赛2解题报告

---恢复内容开始--- 今天50分,我自闭 眼瞎看错了一道题,然后两道题的代码都出了点小毛病,自闭 真的竞赛我要这样可以收拾收拾退役了真的,眼睛不能这么瞎了考试莫得人帮忙改了 如果一切都没问题今天应该有130,啊!!!!!!!!!!!!!!!!! 今天两题可以用堆,一题模拟随便写写就过了,(所以我为什么考这么差) 进入正题 题目一览(其实就3道题)(CZR到底是谁这么爱数学和折磨我们) 24点 小游戏 中位数 题1. 24点 题目描述 1.1 Background CZR很喜欢学数学,但是他数

To myself,to my true feeling ——即将afo的一个蒟蒻的感想

致下个周考试的自己,致未来工作的自己.也,为了今天的自己. 希望,这份美好的回忆,不会忘却,留在心间. 为了自己的理想,奋斗过,努力过. 无论结果,都是那宝贵的珍珠. 记忆繁星,不会忘却那奋斗努力的痕迹. 不知不觉,我已经在学noip的道路上走了两年. 两年间,有所失,有所得. 有欢喜,有伤悲. 记得当时第一次编译通过我的第一道"Hello World"时的开心与兴奋, 也有一晚上想不出一道dp题的伤心. 开始,我觉得计算机只是一个好玩的东西,知道学习的深入,我才了解了更多的知识, 同

一个蒟蒻的成长[日更]

从今天开始记录一下为数不多天的OI历程 8.25 上 今天举行了难得的五校联考,模拟noip,题目的解压密码竟然是$aKnoIp2o18$,对你没有看错!!! 7:50老师?啊啊啊啊,收不到题目啊,还是拿U盘自己拷吧.orz T1 woc 一看图,明显的模拟嘛,呀呵,这咋模拟,手玩?(一个半小时 have pass ) 先去看T2吧(倒),暴力,n3明显会死掉的,优化优化,n2拿个50分算了. T1灵光一闪,打个暴力吧(50) 这该死的T3就给10分暴力分,玩啥,啥?你以为我看出来有规律,就能找

分享一个蒟蒻碰到的盗号

首先是一个好友给我发了一个留言 乍一看还挺正规,扫描二维码,出来这么个界面 扑面而来的是一股莫名的熟悉感(咳咳 几年来的好友盗号事件让我万分警惕,首先输了一个假帐号假密码 结果万万没想到 我tm差点就信了呢 换了个账号密码,结果 盗号无疑了 然后试图用电脑打开这个网站 先后用下图界面的分享到好友.复制链接和浏览器打开再复制链接,结果电脑端无法打开 不过F12还是可以看出一点东西 对,就这么几行代码,但是我不会html,只能看懂个大概(看来得赶紧学html了 总之,专业分析还是让专业的人来吧 对了

一个蒟蒻蠢到一种境界的错误——未完待续

1 .自信的不看样例说明,自信的不手推一下样例,自信的认为选2个点就一定不能重复选 http://www.cnblogs.com/TheRoadToTheGold/p/6379634.html 然而样例说明举例子举得清清楚楚有重复 2.自信的不看输出说明,自信的认为最后一行输不输出换行无所谓http://www.cnblogs.com/TheRoadToTheGold/p/6379634.html 然而输出说明清清楚楚写着最后一行不输出空格 ——持续更新

【一个蒟蒻的挣扎】简单算法

济南DAY1内容,老师讲的非常慢非常细(好容易懂de) 基本原理我就不写啦,这里只是记录一下一些例题 看看例题写写例题,OK 二分 [NKOI]循环赛日程表 二分查找 时间复杂度不超过O(log 2^n) [NKOI3592]人数统计 给出每个同学过题量和m个询问,求每个过题量k有几个 二分查找,L始终指向最左(右)边的k,求出区间后相减,就是答案. 二分快速幂 时间复杂度O(log b) 模板自己想啦 二分答案 跳石头[洛谷P2678] 贪心 方格取数 任务调度问题 分糖果 搜索 健康的荷斯坦

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

赛前没啥时间好好解释了,还有三天2019CSP,大家加油啊!!! ヾ(?°∇°?)?? 背掉它就好啦!!! 我觉得我这一版打得还行就放上来了 #include<cstdio> #include<cstring> #include<iostream> #include<queue> #include<cmath> #include<vector> using namespace std; int n,m,s; int dis[10001

论蒟蒻的自我修养

作为一个蒟蒻,离开大神还有很大一段距离(更不用说神犇了).作为一个想成为SB的SX,自我修养是及其重要的.即使初三老师丧心病狂,也不能放弃这条路恩! 计划: 恩不去MO但是学习他们的那些书~~毕竟数学渣 = ^ = 然后是数据结构...我最弱的一块辣 然后是算法...我也不强 解题思路 啊啊啊!!!差得要命!!! 写程序 啊啊啊!!要死辣!! 所以要多写多练撒!! 要开始刷题了撒!! BZOJ的题目都不会啊!!要死了撒! 估计学一下MO还是有好处的..至少OI MO不分家~~MO主要是数论和排列