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题. 暴力顾名思义,用简单粗暴的方式解题,不以正常的思路思考.能够较好的保证正确性,但是 ...
随机推荐
- JQuery_自带的动画效果
1.方法: show:显示选中元素. hide:隐藏选中元素. toggle:显示或隐藏选中元素. fadeIn:将选中元素的不透明度逐步提升到100%. fadeOut:将选中元素的不透明度逐步降为 ...
- OpenGL学习(1)——创建窗口
这是我的第一篇博客,试着记录学习OpenGL的过程.使用的教程:LearnOpenGL,系统:Deepin 15.9.3,IDE:Qt Creator. 添加头文件 创建窗口用到两个库:GLFW和GL ...
- #个人博客作业week3——微软必应词典的使用
产品的调研和评测 笔者使用的是win8的必应词典客户端. 首先打开客户端,用户界面的设计十分简洁,使用方便.但是词典主页与大多外语软件的设计相仿,例如有每日一句,每日阅读等模块,并没有令人感到新奇的地 ...
- LINUX内核分析第八周学习总结——进程的切换和系统的一般执行过程
LINUX内核分析第八周学习总结——进程的切换和系统的一般执行过程 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/c ...
- Beta版发布说明
我们的作品“校友聊”软件的最终版本于6月19日最终发布了,下面我们将对自己的产品进行介绍. 在使用之前,首先要进行用户注册,用户可以自行设置自己的账号,姓名,密码,签名,头像等信息,头像信息也可以在文 ...
- Sprint 冲刺第三阶段第二天
陈汝婷:播放音乐 1:做播放音乐这个功能时开始没有考虑周全,使用 PS P出来的图竟然没有用上,耗时耗人工.吃一见长一智,以后要考虑周全.还要耗了那么久,音乐的初效果终于出来了. 2:昨天出现的问题, ...
- DOM的基本操作
什么是DOM 1:文档对象模型(DocumentObjectModel,DOM) 2:DOM定义了访问和操作HTML文档的标准方法. 3:DOM将HTML 文档表达为树结构. 其他查询元素的方法: d ...
- [转帖]/etc/security/limits.conf的含义
https://www.cnblogs.com/pzk7788/p/7250723.html /etc/security/limits.conf 是 Linux 资源使用配置文件,用来限制用户对系统资 ...
- [日常工作] Inspur 服务器安装ESXi的简单过程
1. 公司里面使用虚拟化来进行功能测试 性能测试, 现阶段和之前主要是用虚拟机来搞. 前期用过hyperV 但是感觉 没有SystemCenter的VMM的授权比较难搞一些. 所以还是用ESXi的多了 ...
- 日常工作: 应用服务器Oracle驱动问题说明
1. .net使用Oracle驱动的发展等 作为.net线的产品的ERP产品 最初的版本 使用了.net 1.1发布时 微软提供的Oracle的驱动 但是后续微软的.net产品线貌似没有继续发展相应的 ...