这一题我们考虑一个最裸的算法:

我们设$dp[i][j][k][l]$表示当前棋子在$(i,j)$且空格在$(k,l)$时的最小步数

然后显然随便转移一下就好了,时间复杂度为$O(q(nm)^2)$。可以获得$80$分的好成绩(我自测的时候只打了这个)

我们发现这一题有一些很优秀的性质:

首先整个图是静态的,且起点,终点,出现空格的位置均非障碍物。

那么对于这个性质,我们做一些微小的预处理。

考虑到当空格与目标棋子四相邻的时候,棋子才能往空格内移动。那么整个走棋的过程可以理解为:调整空格位置-移动棋子到空格里-调整空格位置

我们设$f[i][j][k][l]$表示在不经过$(i,j)$的情况下,将空格从$(i+wx[k],j+wy[k])$移动到$(i+wx[l],j+wy[l])$的最小步数,其中$wx,wy$满足$|wx[i]+wy[i]|=1$,显然有四种组合。

对于每一个$f[i][j][k][l]$,我们通过一次$bfs$去求解。

预处理$f$的时间复杂度显然为$O(16nm)$。

下面考虑每一组询问:

若起点和终点的坐标相同,那么显然输出$0$就好了。

若起点和终点坐标不相同,我们先考虑将空格移动到起点四相邻的位置,所需要的最小步数显然可以通过一次$bfs$求得。

然后我们设$d[i][j][k]$表示当前棋子在$(i,j)$时,空格在$(i+wx[k],j+wy[k])$的最小步数。

显然随便$bfs$就可以进行更新了。最后的答案显然是$min(d[tx][ty][])$。

时间复杂度$O(16nm+4qnm)$。跑得飞快。

 #include<bits/stdc++.h>
#define M 32
#define INF 16843009
using namespace std;
int n,m,q,mp[M][M]={},dis[M][M]={},d[M][M][]={},f[M][M][][]={};
const int wx[]={,,,-};
const int wy[]={,,-,};
queue<int> qx,qy,qk;
void bfs(int X,int Y){
memset(dis,,sizeof(dis));
qx.push(X); qy.push(Y); dis[X][Y]=;
while(!qx.empty()){
X=qx.front(); qx.pop();
Y=qy.front(); qy.pop();
for(int i=;i<;i++){
int _x=X+wx[i],_y=Y+wy[i];
if(mp[_x][_y]&&dis[_x][_y]>dis[X][Y]+){
dis[_x][_y]=dis[X][Y]+;
qx.push(_x); qy.push(_y);
}
}
}
}
void move(int x,int y){
memset(dis,,sizeof(dis));
qx.push(x); qy.push(y); dis[x][y]=;
while(!qx.empty()){
x=qx.front(); qx.pop();
y=qy.front(); qy.pop();
for(int i=;i<;i++){
int _x=x+wx[i],_y=y+wy[i];
if(mp[_x][_y]&&dis[_x][_y]>dis[x][y]+){
dis[_x][_y]=dis[x][y]+;
qx.push(_x); qy.push(_y);
}
}
}
} void bfs(){
while(!qx.empty()){
int x=qx.front(); qx.pop();
int y=qy.front(); qy.pop();
int k=qk.front(); qk.pop();
for(int i=;i<;i++){
int _x=x+wx[i],_y=y+wy[i];
if(mp[_x][_y]==) continue;
if(d[_x][_y][(i+)&]>d[x][y][k]+f[x][y][k][i]+){
d[_x][_y][(i+)&]=d[x][y][k]+f[x][y][k][i]+;
qx.push(_x); qy.push(_y); qk.push((i+)&);
}
}
}
} int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++) scanf("%d",&mp[i][j]); for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
if(mp[i][j]){
mp[i][j]=;
for(int k=;k<;k++)
if(mp[i+wx[k]][j+wy[k]]){
bfs(i+wx[k],j+wy[k]);
for(int l=;l<;l++)
f[i][j][k][l]=dis[i+wx[l]][j+wy[l]];
}
mp[i][j]=;
} while(q--){
int ex,ey,sx,sy,tx,ty;
cin>>ex>>ey>>sx>>sy>>tx>>ty;
if(sx==tx&&sy==ty){
printf("0\n");
continue;
}
mp[sx][sy]=;
move(ex,ey);
mp[sx][sy]=;
memset(d,,sizeof(d));
for(int i=;i<;i++)
if(mp[sx+wx[i]][sy+wy[i]]){
qx.push(sx);
qy.push(sy);
qk.push(i);
d[sx][sy][i]=dis[sx+wx[i]][sy+wy[i]];
}
bfs();
int minn=INF;
for(int i=;i<;i++)
minn=min(minn,d[tx][ty][i]);
if(minn==INF) printf("-1\n");
else cout<<minn<<endl;
}
}

【NOIP2013】 华容道 bfs预处理+bfs的更多相关文章

  1. BZOJ-1189 紧急疏散evacuate BFS预处理+最大流+二分判定+神建模!!

    绝世污题,垃圾题,浪费我一整天青春! 1189: [HNOI2007]紧急疏散evacuate Time Limit: 10 Sec Memory Limit: 162 MB Submit: 1262 ...

  2. HDU - 1430 魔板 (bfs预处理 + 康托)

    对于该题可以直接预处理初始状态[0, 1, 2, 3, 4, 5, 6, 7]所有可以到达的状态,保存到达的路径,直接打印答案即可. 关于此处的状态转换:假设有初始状态为2,3,4,5,0,6,7,1 ...

  3. 【2016 ICPC亚洲区域赛北京站 E】What a Ridiculous Election(BFS预处理)

    Description In country Light Tower, a presidential election is going on. There are two candidates,   ...

  4. HDU 3533 Escape(BFS+预处理)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3533 题目大意:给你一张n* m的地图,人在起点在(0,0)要到达终点(n,m)有k(k<=10 ...

  5. bzoj 1415(概率dp和bfs预处理)

    感觉挺经典的一道题目. 先用 bfs 预处理下一步走到的位置.因为每一步走法都是固定的,所以可以用dp的方法来做. 1415: [Noi2005]聪聪和可可 Time Limit: 10 Sec  M ...

  6. [NOIP2013]华容道 题解(搜索)

    [NOIP2013]华容道 [题目描述] 这道题根据小时候玩华容道不靠谱的经验还以为是并查集,果断扑街.考后想想也是,数据这么小一定有他的道理. 首先由于是最小步数,所以BFS没跑了.那么我们大可把这 ...

  7. [NOIP2013]华容道 题解

    [NOIP2013]华容道 首先是一种比较显然的做法. 整个棋盘,除了起点,终点和空格,其他的方块是等价的. 对于终点,它始终不会变化,如果搜到终点结束搜索即可,所以我们不需要考虑终点. 所以需要考虑 ...

  8. luogu P1979 [NOIP2013] 华容道

    传送门 这道题中,棋子的移动是要移动到空格上去,所以空格要在棋子旁边才能移动棋子;而棋子移动的方向由空格决定 所以我们可以记三维状态\(di_{i,j,k}\),表示状态为棋子在\((i,j)\),空 ...

  9. LOJ2613 NOIP2013 华容道 【最短路】*

    LOJ2613 NOIP2013 华容道 LINK 这是个好题,具体题意比较麻烦可以直接看LINK中的链接 然后考虑我们可能的移动方式 首先我们需要把白块移动到需要移动块S的附近(附近四格) 然后我们 ...

随机推荐

  1. 2018.08.30 NOIP模拟 kfib(矩阵快速幂+exgcd)

    [输入] 一行两个整数 n P [输出] 从小到大输出可能的 k,若不存在,输出 None [样例输入 1] 5 5 [样例输出] 2 [样例解释] f[0] = 2 f[1] = 2 f[2] = ...

  2. sql join用法(转)

    left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录inner join(等值连接) 只 ...

  3. 初探Java反射机制

    反射库提供了一个非常丰富且精心设计的工具集,以便编写能够动态操纵java代码的程序库.这项功能被大量地应用于JavaBeans中.反射机制提供了在运行状态中获得和调用修改任何一个类的属性和方法的能力. ...

  4. HDU4081 Qin Shi Huang's National Road System 2017-05-10 23:16 41人阅读 评论(0) 收藏

    Qin Shi Huang's National Road System                                                                 ...

  5. hdu 1300 Deck

    题目 分析:对于n张卡片的最佳摆法,我们只需要在n-1张卡片的摆法下面加一张边缘与桌檐重合的卡片,并将所有卡片一起向桌檐外移动.对于一种最佳摆法,其中心一定在桌檐上,所以一定符合杠杆原理,支点是桌檐. ...

  6. linux 通过md5查找重复文件

    代码如下: md5sum *|sort |uniq -w32 -D|awk -F ' ' '{print $2}' uniq 部分参数 -c #在每行前显示该行重复次数. -d #只输出重复的行. - ...

  7. java中的static(包括类前面修饰的static、方法前面修饰的static、成员变量前面修饰的static)

    static是静态修饰符: 什么叫静态修饰符呢?大家都知道,在程序中任何变量或者代码都是在编译时由系统自动分配内存来存储的,而所谓静态就是指在编译后所分配的内存会一直存在,直到程序退出内存才会释放这个 ...

  8. Eclipse C++,Cygwin 64,gcov,lcov 单体&覆盖率测试环境搭建笔记

    1.下载并安装 Eclipse IDE for C/C++ Developers https://eclipse.org/downloads/packages/eclipse-ide-cc-devel ...

  9. 挂起的更改中的“解析”是什么意思?原来是微软错误的翻译

    [2017.4.5 补充] 收到微软TFS产品组的回复,由于版本分支丢失了本来已经修复的内容,并确认下一个版本将修复这个问题. 自从团队资源管理器的"挂起的更改中"可以链接相关工作 ...

  10. 【NumberValidators】类库介绍

    NumberValidators是一个用于验证中国大陆证件.号码是否符合国家标准的类库,因为该类库在昨日已经正式发布1.0.0版本至nuget,所以在此介绍下该类库的具体功能. NumberValid ...