我想动某个点的话,一定要先把空白点移动到这个点旁边,然后调换这个点和空白点,一直重复

那么,我们就可以记一些状态(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)的更多相关文章

  1. SCU-4527 NightMare2(Dijkstra+BFS) !!!错误题解!!!

    错解警告!!! 描述 可怜的RunningPhoton又做噩梦了..但是这次跟上次不大一样,虽然他又被困在迷宫里,又被装上了一个定时炸弹,但是值得高兴的是,他发现他身边有数不清的财宝,所以他如果能带着 ...

  2. CDOJ 1964 命运石之门【最短路径Dijkstra/BFS】

    给定数字n,m(1<=n,m<=500000) 将n变为n*2花费2,将n变为n-3花费3,要求过程中所有数字都在[1,500000]区间内. 求将n变为m的最少花费 思路:建图 将每个数 ...

  3. URAL 1837. Isenbaev&#39;s Number (map + Dijkstra || BFS)

    1837. Isenbaev's Number Time limit: 0.5 second Memory limit: 64 MB Vladislav Isenbaev is a two-time ...

  4. NOIP2013华容道(BFS+乱搞)

    n<=30 * m<=30 的地图上,0表示墙壁,1表示可以放箱子的空地.q<=500次询问,每次问:当空地上唯一没有放箱子的空格子在(ex,ey)时,把位于(sx,sy)的箱子移动 ...

  5. [luogu1979] 华容道

    题面 ​ 先讲点无关的,这道题是真的恶心... ​ 好了,第一眼看到这道题,肯定是准备暴搜的,但是想了一想,省选难度的题目不可能一上来就让你暴搜吧,于是开启了无穷无尽的分析,我们不妨设指定棋子叫做移动 ...

  6. lightoj 1099【dijkstra/BFS】

    题意: 求 1-N 的第二长路,一条路可以重复走 if two or more shortest paths exist, the second-shortest path is the one wh ...

  7. bzoj P1979 华容道【bfs+spfa】

    调死我了-- 首先观察移动方式,需要移动的格子每次移动到相邻格子,一定是先把空白格子挪过去,所以我们得到一种做法,就是bfs预处理出每一个格子的四联通格子之间的空白格子移动距离建边,注意这个移动是不能 ...

  8. hdu1548 奇怪的电梯 dfs dijkstra bfs都可以,在此奉上dfs

    题目链接:http://icpc.njust.edu.cn/Problem/Hdu/5706/ 简单的规定深度进行搜索,代码如下: #include<bits/stdc++.h> usin ...

  9. [题解+总结]NOIP2010-2015后四题汇总

    1.前言 正式开始的第一周的任务--把NOIP2010至NOIP2015的所有D1/2的T2/3写出暴力.共22题. 暴力顾名思义,用简单粗暴的方式解题,不以正常的思路思考.能够较好的保证正确性,但是 ...

随机推荐

  1. linux awk 内置函数实例

    awk内置函数,主要分4种:算数函数.字符串函数.时间函数.一般函数 一.算术函数 以下算术函数执行与 C 语言中名称相同的子例程相同的操作: 函数名 说明 atan2( y, x ) 返回 y/x ...

  2. 印象深刻的bug

    测试中测到一个印象比较深刻的bug,问题出现在web端的电商平台,展示商品的时候每点击一个商品相应的url=~/productid.html,如果知道productid可以直接在url输入跳转到商品详 ...

  3. Netdata---Linux系统性能实时监控平台部署记录

    通常来说,作为一个Linux的SA,很有必要掌握一个专门的系统监控工具,以便能随时了解系统资源的占用情况.下面就介绍下一款Linux性能实时监测工具-Netdata,它是Linux系统实时性能监测工具 ...

  4. sublime text3 安装package control 出现问题解决过程记录

    1.安装package control 失败 通过最简单的自动安装 package control 失败(详见package control官网). 报错展示: File "./python ...

  5. linux第一次读书笔记

    第一章 LINUX内核简介 1.1 Unix的历史 1969年的夏天,贝尔实验室的程序员们在一台PDR-7型机上实现了Unix这个全新的操作系统. 1973年,整个Unix系统用C语言进行了重写,给后 ...

  6. 数学建模-lingo使用

    1.安装启动,软件下载地址:http://pc.xzstatic.com/2017/06/LINGO14 .zip.此为免安装版,打开后双击Lingo11.exe即可启动软件. 2.示例:某商品单位成 ...

  7. 第一个Sprint第一天

    第一个Sprint冲刺的第一天 组员:陈建定 陈友沛 林清松 我们小组选的题目是小学四则运算APP 之前我们都没有做过这个程序,不过我们会尽力完成. 第一阶段的冲刺我们主要分析这个APP的所需的功能, ...

  8. Git的其他用法

    目录: 减少[.git]文件夹的大小和文件数 更换git for windows的文本编辑器 修改已经提交的commit说明 合并commit 解决merge时出现的冲突 回退一个merge 获取某一 ...

  9. java.lang.Exception: No tests found matching Method tes(com.bw.test.Testrefiect) from org.junit.vintage.engine.descriptor.RunnerRequest@3bfdc050 at org.junit.internal.requests.FilterRequest.getRunner

    junit   方法  没有加上注解  @Test java.lang.Exception: No tests found matching Method tes(com.bw.test.Testre ...

  10. logback基本入门

    1. logback的定义 Logback是由log4j创始人设计的另一个开源日志组件,官方网站: http://logback.qos.ch.它当前分为下面下个模块: logback-core:其它 ...