要优先安排历年NOIP题

考虑到要移动,肯定要先把空的格子移动到起点旁边,所以我们对于每一个询问都先bfs一次求出把空格移到起点的四个位置的最短路,而且要保证不能移动起点的方块。

只有空的格子在一个格子四边的时候才可以进行一次移动,所以将一个可行的格子与它周围四个可能的空格出现位置捆绑为一个结点,这样通过移动空格或者把格子移到空格上都可以转移到下一个点。

对于移动格子的边,只要扫一遍判一下合法就可以连上一条为1的边,剩下的可以采取预处理的策略先bfs一遍然后处理空格在一个格子四周移动时的最小位置,bfs的时候注意不能移动当前找到的格子。

这样子一共最多有$n * n * 4 = 900$个点,每一个点搜一遍的时间上界是$n * n * 4 * n * n = O(n ^ {4})$级别的。

对于每一个询问,只要先bfs一遍求出把空格移到起点四边的最短路线,然后丢到队列里跑个最短路就可以了。

还是多写写堆dij吧,戒掉spfa

这样子最后的答案就是终点四周的格子编号的最小值。

注意到bfs函数可以重复利用。

时间复杂度$O((nm)^{2} + q(nm)^{2})$。

Code:

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std; const int L = ;
const int N = ;
const int M = 1e6 + ;
const int inf = 0x3f3f3f3f;
const int dx[] = {-, , , };
const int dy[] = {, , , -}; int n, m, qn, tot, head[N], d[N], a[L][L], dis[L][L];
bool vis[N]; struct Edge {
int to, nxt, val;
} e[M]; inline void add(int from, int to, int val) {
e[++tot].to = to;
e[tot].val = val;
e[tot].nxt = head[from];
head[from] = tot;
} inline void read(int &X) {
X = ;
char ch = ;
int op = ;
for(; ch > ''|| ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} struct Node {
int x, y;
Node(int nowx = , int nowy = ) : x(nowx), y(nowy) {} inline void readIn() {
read(x), read(y);
}
}; inline int id(Node now, int sta) {
return ((now.x - ) * m + now.y - ) * + sta + ;
} void bfs(Node st, Node ed, int sta) {
queue <Node> Q; Q.push(st);
memset(dis, , sizeof(dis)); dis[st.x][st.y] = ; for(; !Q.empty(); ) {
Node out = Q.front(); Q.pop();
for(int i = ; i < ; i++) {
Node in = Node(out.x + dx[i], out.y + dy[i]);
if(!a[in.x][in.y] || (in.x == ed.x && in.y == ed.y) || dis[in.x][in.y]) continue;
dis[in.x][in.y] = dis[out.x][out.y] + ;
Q.push(in);
}
} if(sta == ) return;
for(int i = ; i < ; i++) {
int tox = ed.x + dx[i], toy = ed.y + dy[i];
if((tox == st.x && toy == st.y) || !dis[tox][toy]) continue;
add(id(ed, sta), id(ed, i), dis[tox][toy] - );
}
add(id(ed, sta), id(st, (sta + ) % ), );
} void spfa(Node st, Node ed) {
queue <int> Q;
memset(d, 0x3f, sizeof(d)); for(int i = ; i < ; i++) {
int tox = st.x + dx[i], toy = st.y + dy[i];
if(!dis[tox][toy]) continue;
int now = id(st, i);
Q.push(now);
d[now] = dis[tox][toy] - ;
vis[now] = ;
} for(; !Q.empty(); ) {
int x = Q.front(); Q.pop();
vis[x] = ;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(d[y] > d[x] + e[i].val) {
d[y] = d[x] + e[i].val;
if(!vis[y]) {
vis[y] = ;
Q.push(y);
}
}
}
} int ans = inf;
for(int i = ; i < ; i++)
ans = min(ans, d[id(ed, i)]);
if(ans == inf) puts("-1");
else printf("%d\n", ans);
} int main() {
read(n), read(m), read(qn);
for(int i = ; i <= n; i++)
for(int j = ; j <= m; j++)
read(a[i][j]); for(int i = ; i <= n; i++)
for(int j = ; j <= m; j++) {
if(!a[i][j]) continue;
for(int k = ; k < ; k++) {
int tox = i + dx[k], toy = j + dy[k];
if(a[tox][toy]) bfs(Node(tox, toy), Node(i, j), k);
}
} for(Node bla, st, ed; qn--; ) {
bla.readIn(), st.readIn(), ed.readIn();
if(st.x == ed.x && st.y == ed.y) {
puts("");
continue;
}
bfs(bla, st, );
spfa(st, ed);
} return ;
}

最新文章

  1. 搭建OpenGL环境-Windows/VS2013
  2. Webdriver配合Tesseract-OCR 自动识别简单的验证码
  3. MSDN Library for vs 2010安装及使用(MSDN Library)
  4. 【Java每日一题】20161116
  5. NOI 2015 荷马史诗【BZOJ 4198】k叉Huffman树
  6. ios高版本SDK在低版本真机调试
  7. Diskpart挂载/卸载VHD
  8. processon完全装逼指南
  9. 找两个string[ ]里不同的元素
  10. Android学习记录:界面设计
  11. 压缩空格的函数以及BCD码与ASCII相互转换函数
  12. iOS UIPrintInteractionController在iPad的 iOS10 和 11上的奇怪bug
  13. Windows上安装nodejs版本管理器nvm
  14. 伪分布式hbase数据迁移汇总
  15. tensorflow中moving average的用法
  16. 如何使用LinkedHashMap来实现一个LruCache
  17. 日期date出参入参和timestamp转化
  18. double转换为int以及浮点型相加损失精度问题
  19. VMWare链接克隆 和 完整克隆
  20. 【wireshark】插件开发(四):Lua插件Post-dissector和Listener

热门文章

  1. 关于nginx访问 静态文件 403 的错误
  2. C中的时间函数的用法
  3. angular +H5 上传图片 与预览图片
  4. 关于打包后提示无法连接到mongodb的情况
  5. Activiti:MalformedByteSequenceException: 3 字节的 UTF-8 序列的字节 3 无效。
  6. kafka集群安装和kafka-manager
  7. c# pictureBox 循环播放图片
  8. Python类(六)-静态方法、类方法、属性方法
  9. 第十五章 深入分析iBatis框架之系统架构与映射原理(待续)
  10. Firemonkey Android IOS 图标