某王  老师给我们考了一场noip2013的真题。。。心态爆炸!

题目大意:

有一个n*m的棋盘,每个格子上都有一个棋子,有些格子上的棋子能够移动(可移动的棋子是固定的),棋盘中有一个格子是空的,仍何可移动的棋子都能够与空格子交换位置。现在有q个询问,每个询问给出kx,ky,sx,sy,ex,ey,分别为空白格子的坐标,要你移动的棋子,目标位置。对于每个询问,要求你求出,把要求你移动的棋子移到目标位置最少移动几次。

思路分析:

首先讲一下暴力做法吧。

这应该大家都能想得到,BFS嘛,记录要求我们移动的棋子(暂且记作1号格子)当前的位置和空白格子(记作2号格子)的位置,当2移动到1旁边时,那么1就可以与2交换位置。

而正解就是基于暴力展开的。。。

我们发现其实当2移动到1旁边后,便产生了很多无用的状态,我们只需要知道2在1周围的几个状态就够了,因为1格子进行移动时,无非就是和它周围的几个格子交换位置,而交换位置后2仍然在1的周围,所以我们只需要知道2在从1周围的4个格子走到另一个格子的最小花费即可。

我们记一个三元组(x,y,k)其中x,y表示1号棋子的坐标,k表示2号棋子相对1号棋子的位置(0表示在1的上面,1表示在1的右边,2表示在1的左边,3表示在1的下面),当然一心想要偷懒的我粗暴地把三元组压成了一个数,是这么压的(x,y,k)=k*n*m+(x-1)*m+y,嗯,免得你们看不懂代码。。。

那么根据我们先前讲的,设计两种连边:

1、可以在(x,y,0~3)与(x,y,0~3)之间设计一条长度为空白格子从一个位置(x,y的上下左右)走到另一个位置(x,y的上下左右)的最小花费。

2、在(x,y,k)与(x+dx[k],y+dy[k],3-k)之间连一条边,其意义便是1号格子与2号格子交换了位置。(现在知道我这么设计方向的(shi)用(wei)心(le)良(tou)苦(lan)了吧)

先把连边预处理出来,然后我们只要第一次计算出初始位置的2号格子移动到1号格子的上下左右的最小花费(可以BFS暴力做)之后,跑一边Dijkstra就完事儿了!

代码实现:

type
hehe=record
dist,id:longint;
end;
haha=record
x,y,dist:longint;
end;
var
next,vet,dist:array[1..200000]of longint;
f:array[1..2000000]of hehe;
a:array[1..90000]of haha;
d,fir,visit:array[1..48000]of longint;
map,vis:array[-50..50,-50..50]of longint;
dx,dy:array[0..3]of longint;
sx,sy,ex,ey,kx,ky,xx,yy,n,m,q,i,j,ii,jj,tot,weight,x,y,oo,cost,ans,z,x1,x2,y1,y2:longint;
procedure add(x,y,z:longint);
begin
inc(tot);
next[tot]:=fir[x];
fir[x]:=tot;
vet[tot]:=y;
dist[tot]:=z;
end;
function min(x,y:longint):longint;
begin
if x<y then exit(x) else exit(y);
end;
procedure swap(x,y:longint);
var
t:hehe;
begin
t:=f[x]; f[x]:=f[y]; f[y]:=t;
end;
procedure up(x:longint);
begin
if x=1 then exit;
if f[x].dist<f[x div 2].dist then begin swap(x,x div 2); up(x div 2); end;
end;
procedure down(x:longint);
var
k:longint;
begin
if x*2>n then exit;
k:=min(f[x*2].dist,f[x*2+1].dist);
if f[x].dist>k then
if k=f[x*2].dist then begin swap(x,x*2); down(x*2); end
else begin swap(x,x*2+1); down(x*2+1); end;
end;
procedure push(x,id:longint);
begin
inc(weight);
f[weight].dist:=x;
f[weight].id:=id;
up(weight);
end;
procedure pop;
begin
x:=f[1].id;
f[1].dist:=f[weight].dist;
f[1].id:=f[weight].id;
f[weight].dist:=oo;
f[weight].id:=oo;
dec(weight);
down(1);
end;
procedure dijkstra;
var
y,i:longint;
begin
fillchar(visit,sizeof(visit),0);
while weight>0 do
begin
pop;
if x>4800 then continue;
if d[x]>=oo then break;
if visit[x]=1 then continue;
visit[x]:=1;
i:=fir[x];
while i<>0 do
begin
y:=vet[i];
if (dist[i]<oo)and(d[y]>d[x]+dist[i]) then
begin d[y]:=d[x]+dist[i]; push(d[y],y); end;
i:=next[i];
end;
end;
end;
function bfs(nx,ny,x1,y1,x2,y2:longint):longint;
var
head,tail,dist,xx,yy,x,y,i:longint;
begin
if map[x1,y1]+map[x2,y2]<>2 then exit(oo);
if (x1=x2)and(y1=y2) then exit(0);
fillchar(vis,sizeof(vis),0);
head:=0; tail:=1; bfs:=maxlongint;
a[1].x:=x1; a[1].y:=y1; a[1].dist:=0; vis[x1,y1]:=1;
while head<>tail do
begin
inc(head);
x:=a[head].x; y:=a[head].y; dist:=a[head].dist;
for i:=0 to 3 do
begin
xx:=x+dx[i]; yy:=y+dy[i];
if ((xx<>nx)or(yy<>ny))and(map[xx,yy]=1)and(vis[xx,yy]=0) then
begin
inc(tail);
a[tail].x:=xx; a[tail].y:=yy; a[tail].dist:=dist+1;
vis[xx,yy]:=1;
if (xx=x2)and(yy=y2) then exit(dist+1);
end;
end;
end;
end;
begin
read(n,m,q);
for i:=1 to n do
for j:=1 to m do
read(map[i,j]);
dx[0]:=-1; dy[1]:=1; dy[2]:=-1; dx[3]:=1;
for i:=1 to n do
for j:=1 to m do
if map[i,j]=1 then
for ii:=0 to 3 do
begin
x1:=i+dx[ii]; y1:=j+dy[ii]; x2:=i; y2:=j;
if map[x1,y1]+map[x2,y2]=2 then
begin
add(ii*n*m+(x2-1)*m+y2,(3-ii)*n*m+(x1-1)*m+y1,1);
end;
for jj:=0 to 3 do
begin
x2:=i+dx[jj]; y2:=j+dy[jj];
if (ii<>jj)and(map[x1,y1]+map[x2,y2]=2) then
begin
cost:=bfs(i,j,x1,y1,x2,y2);
add(ii*n*m+(i-1)*m+j,jj*n*m+(i-1)*m+j,cost);
end;
end;
end;
while q>0 do
begin
read(kx,ky,sx,sy,ex,ey);
fillchar(d,sizeof(d),$1f);
oo:=d[1];
fillchar(f,sizeof(f),$1f);
weight:=0;
if (sx=ex)and(sy=ey) then
begin
writeln(0);
dec(q);
continue;
end;
for i:=0 to 3 do
begin
x:=sx+dx[i]; y:=sy+dy[i];
if map[x,y]=1 then
begin
d[i*n*m+(sx-1)*m+sy]:=bfs(sx,sy,kx,ky,x,y);
push(d[i*n*m+(sx-1)*m+sy],i*n*m+(sx-1)*m+sy);
end;
end;
dijkstra;
ans:=oo;
for i:=0 to 3 do
begin
z:=i*n*m+(ex-1)*m+ey;
if d[z]<=ans then ans:=d[z];
end;
if ans=oo then writeln(-1) else writeln(ans);
dec(q);
end;
end.

NOIP提高组2013 D2T3 【华容道】的更多相关文章

  1. NOIP提高组 2013货车运输

    觉得题目水的离开 不屑的大佬请离开 不会图论的请离开 ……. 感谢您贡献的访问量 ————————————华丽的分割线———————————— 题面: 题目描述 A 国有 n 座城市,编号从 1 到 ...

  2. 题解 【luoguP1967 NOIp提高组2013 货车运输】

    题目链接 题解 题意 给你一个无向图,求两个点之间的一条路径,使路径上的最小值最大 算法:Kruskal最大生成树+倍增lca 分析 首先容易知道,答案一定在该图的最大生成树上 之后问题便转换成了树上 ...

  3. 洛谷P1966 火柴排队[NOIP提高组2013]

    我确信我应该是做过这道题……就当再写一遍好了. 贪心思想,一番证明得出a和b数组中最小对最小,次小对次小……时解最优.那么先处理出a,b之间的对应关系,然后按照该关系求a或者b的逆序对数量就是答案 / ...

  4. NOIP提高组2016 D2T3 【愤怒的小鸟】

    貌似还没有写过状压DP的题目,嗯,刚好今天考了,就拿出来写一写吧. 题目大意: 额,比较懒,这次就不写了... 思路分析: 先教大家一种判断题目是不是状压DP的方法吧. 很简单,那就是--看数据范围! ...

  5. NOIP提高组2004 合并果子题解

    NOIP提高组2004 合并果子题解 描述:在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消 ...

  6. 计蒜客 NOIP 提高组模拟竞赛第一试 补记

    计蒜客 NOIP 提高组模拟竞赛第一试 补记 A. 广场车神 题目大意: 一个\(n\times m(n,m\le2000)\)的网格,初始时位于左下角的\((1,1)\)处,终点在右上角的\((n, ...

  7. 1043 方格取数 2000 noip 提高组

    1043 方格取数  2000 noip 提高组 题目描述 Description 设有N*N的方格图(N<=10,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0.如下图所示(见样 ...

  8. [NOIP提高组2018]货币系统

    [TOC] 题目名称:货币系统 来源:2018年NOIP提高组 链接 博客链接 CSDN 洛谷博客 洛谷题解 题目链接 LibreOJ(2951) 洛谷(P5020) 大视野在线评测(1425) 题目 ...

  9. NOIP提高组初赛难题总结

    NOIP提高组初赛难题总结 注:笔者开始写本文章时noip初赛新题型还未公布,故会含有一些比较老的内容,敬请谅解. 约定: 若无特殊说明,本文中未知数均为整数 [表达式] 表示:在表达式成立时它的值为 ...

随机推荐

  1. 【python开发】迈出第一步,这可能是我唯一一次的Python开发了

    好久没写博了,今天就瞎唠唠吧 背景: 组内有个测试平台,是基于Python2+tornado 框架写的,之前自己维护了一套系统的UIweb自动化代码,现在需要集成进去.这很可能是自己唯一一次基于pyt ...

  2. MAC 上编译安装nginx-rtmp-module 流媒体服务器

    MAC 上编译安装nginx-rtmp-module 流媒体服务器 记录踩坑过程 下载nginx和nginx-rtmp-module wget http://nginx.org/download/ng ...

  3. 网址中的静态资源 public

     客户端浏览器收到的HTML响应内容中如果带有 link img script video audio 等带有src或者href标签时候,这些都是外部链接资源请求url.浏览器会默认自动性的对这些资源 ...

  4. Docker启动失败

    报错信息: Job for docker.service failed because the control process exited with error code. See "sy ...

  5. Spring Boot入门,源码解析

    目录 1.Spring Boot简介 2.微服务 3.Spring Boot HelloWorld 3.1 创建一个Maven工程 3.2 导入依赖Spring Boot相关的依赖 3.3 编写一个主 ...

  6. Effective Objective-C 的读书笔记

    本文主要是摘录了 <Effective Objective-C 2.0>一书中提到的编写高质量iOS 代码的几个方法. 1 熟悉Objective -C 1.1 OC 起源 OC 为C语言 ...

  7. Python 面试题 字符串 删除多少个字符使得出现做多的字符数量大于等于字符串长度的一半.

    str1 = input() num = {} for i in set(str1): num[i]=str1.count(i) max_value = max(num.values()) n=abs ...

  8. Golang多线程简单斗地主

    多线程,通道,读写锁(单写多读),随机(洗牌),是本文涉及的主要知识点. 先看一下做出来的效果,因为是实验程序,跟真实的斗地主还是有差距,理解万岁! [发牌员]:洗牌咯. 刷刷刷... [发牌员]:牌 ...

  9. Keepalived之高可用LVS集群

    前文我们聊了下keepalived的邮件通知相关配置,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13645163.html:今天我们来说说keepalive ...

  10. 掌控安全sql注入靶场pass-05

    1.判断注入点 1 and 1=1 1 and 1=2 考虑存在布尔盲注 布尔盲注解释 当不能像前面那样直接在网页中显示我们要的数据时就需要用到盲注,来得到数据库之类的名字.基于布尔的盲注就是通过判断 ...