luogu1979 华容道 (dijkstra+bfs)
我想动某个点的话,一定要先把空白点移动到这个点旁边,然后调换这个点和空白点,一直重复
那么,我们就可以记一些状态(x,y,s) (s={0,1},{0,-1},{1,0},{-1,0}),表示我要动的点在(x,y),然后空白点在(x+s.x,y+s.y)
这样的话我们就可以建图:$(x,y,s)-1->(x+s.x,y+s.y,s^{-1})$ (s^{-1}表示一个相反的方向,比如如果s是右边的话,那它就是左边)
$(x,y,s)-C(x,y,s+s.x,y+s.y,x+i.x,y+i.y)->(x,y,i)$ 其中,C(a,b,c,d,e,f)表示我目前这个点在(a,b),空白点在(c,d),要把空白点挪到(e,f)的最小步数,而且挪的过程中不能经过(a,b)(要不然会把要动的那个点换走)
这样的话,就可以一边bfs算出C的值,一边跑最短路了。
然而复杂度$O(q*(mn)^2)$,过不去。
考虑预处理出C,直接做显然不行($mn^3$),但其实我们要用到C的情况,都是空白点在要处理的点的旁边的,那它就可以压缩成(x,y,s,tx,ty),是900*4*900的。
当然,一开始我们的空白点和要做的点并没有在一起,只要再单独bfs一下,先把空白点挪到它边上就可以了。
要注意有起始点和目标点相同的情况,要判掉。
#include<bits/stdc++.h>
#define pa pair<int,int>
#define pa2 pair<int,Node>
#define ll long long
using namespace std;
const int maxn=; inline ll rd(){
ll x=;char c=getchar();int neg=;
while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x*neg;
} struct Node{
int x,y,s;
Node (int x1,int x2,int x3){x=x1,y=x2,s=x3;}
};
int f[maxn][maxn],N,M,Q,dis[maxn][maxn][][maxn][maxn],dis2[maxn][maxn][];
int step[][]={{,},{,-},{,},{-,}};
bool can[maxn][maxn],flag[maxn][maxn],flag2[maxn][maxn][];
queue<pa > q;
priority_queue<pa2,vector<pa2>,greater<pa2> > q2; bool operator < (Node a,Node b){return a.x<b.x;} int bfs1(int a,int b,int c,int x0,int y0){
memset(flag,,sizeof(flag));
while(!q.empty()) q.pop();q.push(make_pair(x0,y0));
dis[a][b][c][x0][y0]=;
while(!q.empty()){
int x=q.front().first,y=q.front().second;q.pop();
for(int i=;i<=;i++){
int xx=x+step[i][],yy=y+step[i][];
if(!flag[xx][yy]&&can[xx][yy]){
q.push(make_pair(xx,yy));
dis[a][b][c][xx][yy]=dis[a][b][c][x][y]+;
}
}flag[x][y]=;
}
} int dijkstra(int ex,int ey,int sx,int sy,int tx,int ty){
if(sx==tx&&sy==ty) return ;
memset(dis2,-,sizeof(dis2));memset(flag2,,sizeof(flag2));
while(!q2.empty()) q2.pop();
can[sx][sy]=;memset(dis[][][],-,sizeof(dis[][][]));
bfs1(,,,ex,ey);
for(int i=;i<=;i++){
int xx=sx+step[i][],yy=sy+step[i][];
if(dis[][][][xx][yy]!=-){
dis2[xx][yy][i^]=dis[][][][xx][yy]+;
q2.push(make_pair(dis2[xx][yy][i^],Node(xx,yy,i^)));
}
}can[sx][sy]=;
while(!q2.empty()){
Node p=q2.top().second;q2.pop();if(flag2[p.x][p.y][p.s]) continue;
for(int i=;i<=;i++){
int xx=p.x+step[i][],yy=p.y+step[i][];
if(dis[p.x][p.y][p.s][xx][yy]!=-){
if(dis2[xx][yy][i^]==-||dis2[xx][yy][i^]>dis[p.x][p.y][p.s][xx][yy]+dis2[p.x][p.y][p.s]+){
dis2[xx][yy][i^]=dis[p.x][p.y][p.s][xx][yy]+dis2[p.x][p.y][p.s]+;
q2.push(make_pair(dis2[xx][yy][i^],Node(xx,yy,i^)));
}
}
}flag2[p.x][p.y][p.s]=;
}int re=-;
for(int i=;i<=;i++){
if(dis2[tx][ty][i]==-) continue;
if(re==-) re=dis2[tx][ty][i];
else re=min(re,dis2[tx][ty][i]);
}return re;
} int main(){
int i,j,k;
N=rd(),M=rd();Q=rd();
for(i=;i<=N;i++){
for(j=;j<=M;j++) can[i][j]=rd();
}
memset(dis,-,sizeof(dis));
for(i=;i<=N;i++){
for(j=;j<=M;j++){
if(!can[i][j]) continue;can[i][j]=;
for(k=;k<=;k++){
int ii=i+step[k][],jj=j+step[k][];
if(can[ii][jj]) bfs1(i,j,k,ii,jj);
}can[i][j]=;
}
}
for(i=;i<=Q;i++){
int x1=rd(),x2=rd(),x3=rd(),x4=rd(),x5=rd(),x6=rd();
printf("%d\n",dijkstra(x1,x2,x3,x4,x5,x6));
}
return ;
}
luogu1979 华容道 (dijkstra+bfs)的更多相关文章
- SCU-4527 NightMare2(Dijkstra+BFS) !!!错误题解!!!
错解警告!!! 描述 可怜的RunningPhoton又做噩梦了..但是这次跟上次不大一样,虽然他又被困在迷宫里,又被装上了一个定时炸弹,但是值得高兴的是,他发现他身边有数不清的财宝,所以他如果能带着 ...
- CDOJ 1964 命运石之门【最短路径Dijkstra/BFS】
给定数字n,m(1<=n,m<=500000) 将n变为n*2花费2,将n变为n-3花费3,要求过程中所有数字都在[1,500000]区间内. 求将n变为m的最少花费 思路:建图 将每个数 ...
- URAL 1837. Isenbaev's Number (map + Dijkstra || BFS)
1837. Isenbaev's Number Time limit: 0.5 second Memory limit: 64 MB Vladislav Isenbaev is a two-time ...
- NOIP2013华容道(BFS+乱搞)
n<=30 * m<=30 的地图上,0表示墙壁,1表示可以放箱子的空地.q<=500次询问,每次问:当空地上唯一没有放箱子的空格子在(ex,ey)时,把位于(sx,sy)的箱子移动 ...
- [luogu1979] 华容道
题面 先讲点无关的,这道题是真的恶心... 好了,第一眼看到这道题,肯定是准备暴搜的,但是想了一想,省选难度的题目不可能一上来就让你暴搜吧,于是开启了无穷无尽的分析,我们不妨设指定棋子叫做移动 ...
- lightoj 1099【dijkstra/BFS】
题意: 求 1-N 的第二长路,一条路可以重复走 if two or more shortest paths exist, the second-shortest path is the one wh ...
- bzoj P1979 华容道【bfs+spfa】
调死我了-- 首先观察移动方式,需要移动的格子每次移动到相邻格子,一定是先把空白格子挪过去,所以我们得到一种做法,就是bfs预处理出每一个格子的四联通格子之间的空白格子移动距离建边,注意这个移动是不能 ...
- hdu1548 奇怪的电梯 dfs dijkstra bfs都可以,在此奉上dfs
题目链接:http://icpc.njust.edu.cn/Problem/Hdu/5706/ 简单的规定深度进行搜索,代码如下: #include<bits/stdc++.h> usin ...
- [题解+总结]NOIP2010-2015后四题汇总
1.前言 正式开始的第一周的任务--把NOIP2010至NOIP2015的所有D1/2的T2/3写出暴力.共22题. 暴力顾名思义,用简单粗暴的方式解题,不以正常的思路思考.能够较好的保证正确性,但是 ...
随机推荐
- nginx反向代理中proxy_set_header 运维笔记
Nginx proxy_set_header:即允许重新定义或添加字段传递给代理服务器的请求头.该值可以包含文本.变量和它们的组合.在没有定义proxy_set_header时会继承之前定义的值.默认 ...
- python基础学习笔记(五)
字符串基本操作 所有标准的序列操作(索引.分片.乘法.判断成员资格.求长度.取最小值和最大值)对字符串同样适用,前面已经讲述的这些操作.但是,请注意字符串都是不可变的. 字符串的方法: 字符串从str ...
- C# wkhtmltopdf 将html转pdf(详解)
https://www.cnblogs.com/louby/p/905198.html转自,看文章只放了代码看起来云里雾里的,在此做些解析 使用说明: 1.首先呢,得安装下软件,地址下面有链接,文件里 ...
- 【Deep Hash】NINH
[CVPR 2015] Simultaneous Feature Learning and Hash Coding with Deep Neural Networks [paper] Hanjiang ...
- java中for循环的几种方式
比如定义一个数组int a[]={1, 2, 3, 4},下面我们罗列一下遍历这个数组的方法 1 for(;;) 这也是最常用的方法,不多做解释.代码如下 int a[] = {1, 2, 3, 4} ...
- JAVA中方法和变量在继承中的覆盖和隐藏
出处:http://renyanwei.iteye.com/blog/258304 我们知道,在JAVA中,子类可以继承父类,如果子类声明的方法与父类有重名的情况怎么办,大伙儿都知道要是重写,但是实际 ...
- 接口(interface)与多态
1. 接口(interface)是抽象方法与常量值的集合: 2. 从本质上来讲,接口是一种特殊的抽象类,这种抽象类中只包含常量与方法的定义,而没有变量和方法的实现: 3. 接口中声明的属性默认为:pu ...
- MyBatis 返回类型resultType为map时的null值不返回问题
问题一: 查询结果集中 某字段 的值为null,在map中不包含该字段的key-value对 解决:在mybatis.xml中添加setting参数 <!-- 在null时也调用 sett ...
- type=hidden
非常值得注意的一个,通常称为隐藏域:如果一个非常重要的信息需要被提交到下一页,但又不能或者无法明示的时候. 一句话,你在页面中是看不到hidden在哪里.最有用的是hidden的值.
- 基于SSH实现员工管理系统之框架整合篇
本篇文章来源于:https://blog.csdn.net/zhang_ling_yun/article/details/77803178 以下内容来自慕课网的课程:基于SSH实现员工管理系统之框架整 ...