P1979 华容道

题意

题目描述

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

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

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

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

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

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

给定一个棋盘,游戏可以玩\(q\)次,当然,每次棋盘上固定的格子是不会变的,但是棋盘上空白的格子的初始位置、指定的可移动的棋子的初始位置和目标位置却可能不同。第\(i\)次玩的时候,空白的格子在第\(EX_i\)行第\(EY_i\)列,指定的可移动棋子的初始位置为第\(SX_i\)行第\(SY_i\)列,目标位置为第\(TX_i\)行第\(TY_i\)列。

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

输入输出格式

输入格式:

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

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

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

输出格式:

共\(q\)行,每行包含\(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

输出样例:

2
-1

说明

【输入输出样例说明】

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

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

移动过程如下:

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

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

【数据范围】

对于\(30 \%\)的数据,\(1 \leq n,m \leq 10,q=1\);

对于\(60 \%\)的数据,\(1 \leq n,m \leq 30,q \leq 10\);

对于\(100 \%\)的数据,\(1 \leq n,m \leq 30,q \leq 500\)。

思路

怨念--;

这显然是一道爆搜题,只需要搜索就能过了。

搜个锤子啊,要硬搜能过这题还会成为\(NOIP \ 2013\)的毒瘤题?我打的暴力只有\(25\)分,然而logeadd大佬有\(80\)分。

可不可以优化一下呢?其实这道题在\(bfs\)的过程中只需要记录空白格子所在位置以及需要移动的那颗棋子的位置就好了,所以我们不妨把每个\((sx,sy,ex,ey)\)状态看作一个结点,把他向所有可以转移到的点连边,当\((sx,sy)\)转移到\((tx,ty)\),\((ex,ey)\)转移到终点周围的某个格子时,统计答案,那么我们就可以用\(SPFA\)来写。

但是这样的\(SPFA\)边权只有\(1\),不就相当于是优秀一点的\(bfs\)吗?相当于我们没有做到任何的优化啊(虽然我依靠这个卡到了\(80\)分)。

能不能精简一点我们点的数量呢?

想想看,要是我们玩华容道的话,会怎么做?首先我们要把空格子“运”到那颗棋子(叫它钦定棋子好了)旁边,然后钦定棋子移动到空格子上,空格子再在保证钦定棋子位置不改变的情况下,移动到它的前面,继续“运”...

诶,那有效的状态不就是空格子在钦定棋子旁边的状态吗?这样,我们状态记录就可以变成\((sx,sy,k)\),\(k\)表示在钦定棋子的哪个方位。点的数量一下子就从\(n^4\)变成了\(n^2\)级别的。

具体怎么办呢?对于每一个位置,我们统计空格子不经过钦定棋子到达它的另一方位的最短路径,再建空格子与钦定棋子交换这一操作的边,就可以跑\(n^2\)级别的\(SPFA\)了。

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int MAXN=5005;
int n,m,q,G[35][35],dis[35][35],d[MAXN];
int cnt,top[MAXN],to[MAXN<<3],len[MAXN<<3],nex[MAXN<<3];
bool vis[MAXN];
int a[4]={-1,+0,+1,+0};
int b[4]={+0,+1,+0,-1};
inline int read()
{
int re=0;
char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
return re;
}
inline int f(int x,int y){return (x-1)*m*4+(y-1)*4;}
inline void add_edge(int x,int y,int z){to[++cnt]=y,len[cnt]=z,nex[cnt]=top[x],top[x]=cnt;}
void bfs(int ex,int ey,int sx,int sy,int z)
{
memset(dis,-1,sizeof dis);
dis[sx][sy]=1,dis[ex][ey]=0;
queue<PII>Q;
Q.push(make_pair(ex,ey));
while(!Q.empty())
{
int x=Q.front().first,y=Q.front().second;Q.pop();
for(int i=0;i<4;i++)
{
int dx=x+a[i],dy=y+b[i];
if(!G[dx][dy]||dis[dx][dy]!=-1) continue;
dis[dx][dy]=dis[x][y]+1;
Q.push(make_pair(dx,dy));
}
}
if(z==4) return ;
int id=f(sx,sy);
for(int i=0;i<4;i++)
if(dis[sx+a[i]][sy+b[i]]>0)
add_edge(id+z,id+i,dis[sx+a[i]][sy+b[i]]);
add_edge(id+z,f(ex,ey)+(z+2)%4,1);
}
void SPFA(int sx,int sy)
{
queue<int>Q;
memset(d,0x3f,sizeof d);
int id=f(sx,sy);
for(int i=0;i<4;i++)
if(dis[sx+a[i]][sy+b[i]]!=-1)
{
vis[id+i]=true;
d[id+i]=dis[sx+a[i]][sy+b[i]];
Q.push(id+i);
}
while(!Q.empty())
{
int now=Q.front();Q.pop();
vis[now]=false;
for(int i=top[now];i;i=nex[i])
if(d[to[i]]>d[now]+len[i])
{
d[to[i]]=d[now]+len[i];
if(!vis[to[i]])
{
vis[to[i]]=true;
Q.push(to[i]);
}
}
}
}
int main()
{
n=read(),m=read(),q=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
G[i][j]=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(G[i][j])
for(int k=0;k<4;k++)
if(G[i+a[k]][j+b[k]])
bfs(i+a[k],j+b[k],i,j,k);
while(q--)
{
int ex=read(),ey=read(),sx=read(),sy=read(),tx=read(),ty=read();
if(sx==tx&&sy==ty)
{
puts("0");
continue;
}
bfs(ex,ey,sx,sy,4);
SPFA(sx,sy);
int id=f(tx,ty);
int ans=0x3f3f3f3f;
for(int i=0;i<4;i++) ans=min(ans,d[id+i]);
printf("%d\n",ans==0x3f3f3f3f?-1:ans);
}
return 0;
}

Luogu P1979 华容道(bfs+最短路)的更多相关文章

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

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

  2. JZYZOJ1442 [noip2013]华容道 bfs 最短路 剪枝

    http://172.20.6.3/Problem_Show.asp?id=1442 想到最短路的简直神了,如果我写我大概只能写一个30分的bfs. 从数据范围可以看出思路是bfs剪枝,但这里的剪枝是 ...

  3. luogu P1979 华容道

    solution 被假hash可了半天....sadQAQ code // luogu-judger-enable-o2 #include<queue> #include<cstdi ...

  4. 洛谷 P1979 华容道 解题报告

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

  5. 洛谷P1979 华容道(70分 暴力)

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

  6. POJ 2251 Dungeon Master (BFS最短路)

    三维空间里BFS最短路 #include <iostream> #include <cstdio> #include <cstring> #include < ...

  7. 【bzoj5049】[Lydsy九月月赛]导航系统 并查集+双向BFS最短路

    题目描述 给你一张 $n$ 个点 $m$ 条边的随机图,边权为1.$k$ 次询问两点间最短路,不连通则输出-1. 输入 第一行包含3个正整数n,m,k(2<=n<=100000,1< ...

  8. 【bzoj1189】[HNOI2007]紧急疏散evacuate BFS最短路+动态加边网络流

    题目描述 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一块空地:如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以 ...

  9. BZOJ 1195 [HNOI2006]最短母串 (Trie图+状压+bfs最短路)

    BZOJ1195 LOJ10061 题目大意:给你$n$个模式串,求一个最短且字典序最小的文本串并输出这个串,$n<=12,len<=50$ 首先对所有模式串构造$Trie$图,$Trie ...

随机推荐

  1. 压测:mysqlslap

    MySQL从5.1.4版开始带有一个压力测试工具mysqlslap,通过模拟多个并发客户端访问mysql来执行测试,使用起来非常简单,通过mysqlslap –help可以获得可用的选项.这里列一些主 ...

  2. vue+layui制作列表页

    优点: 1.选用layui国产. 2.layui有一套完整的前端框架,基本哪来就可以用. 3.选用vue去掉了很多页面元素js拼接的繁琐,及不易修改. 4.vue里面还有一些过滤器等,用起来很方便. ...

  3. CF596D Wilbur and Trees

    题意:有一些高度为h的树在数轴上.每次选择剩下的树中最左边或是最右边的树推倒(各50%概率),往左倒有p的概率,往右倒1-p. 一棵树倒了,如果挨到的另一棵树与该数的距离严格小于h,那么它也会往同方向 ...

  4. 你必须知道的.NET Day1

  5. 关于Synthesis

    1,当追求面积最小时 会以牺牲Fmax为代价,可以使用一下setting: fit_pack_for_density=on fit_report_lab_usage_stats=on 可在 .qsf ...

  6. 三次面试总结以及今后的todolist

    金三银四跳槽季,按耐不住蠢蠢欲动的跳槽心,投了好多家的前端招聘,目前面了三家,有把握的零家.古人吾日三省吾身,我没那么高的觉悟,三面省一下自身,太咸鱼了是的我就是这么觉得的. 第一家公司在景田,很远, ...

  7. ArcMap10.2 中制作符号库

    今天在发布地图服务时,发现地图中的3D符号没法用,出现”00013“错误,如下:

  8. Java-Druid:目录

    ylbtech-Java-Druid:目录 1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返回顶部   作者:ylbtech出处:http://yl ...

  9. SpringBoot学习笔记(三):SpringBoot集成Mybatis、SpringBoot事务管理、SpringBoot多数据源

    SpringBoot集成Mybatis 第一步我们需要在pom.xml里面引入mybatis相关的jar包 <dependency> <groupId>org.mybatis. ...

  10. OpenCASCADE 平面求交

    OpenCASCADE 平面求交 eryar@163.com OpenCASCADE提供了类IntAna_QuadQuadGeo用来计算两个二次曲面quadric(球面.圆柱面.圆锥面及平面,平面是二 ...