python华容道最短路径_【题解】 NOIp2013 华容道 最短路+状态压缩 Luogu1979

Legend

Link \(\textrm{to Luogu}\)。

题目描述就不搬了。

Editorial

显然,可以看做空位在一直移动,移动到目标棋子旁边就可以交换一下空位和目标棋子的位置,最后要让目标棋子到目标位置。

有一个非常显然的做法记录节点状态为:【空位坐标】+【目标棋子坐标】的形式。直接 0-1 bfs 就是 \(O(Tn^2m^2)\) 的,足够拿到 \(60\) 分。

想办法优化状态,有什么状态是无效的?显然,目标棋子会移动当且仅当空位在目标棋子相邻格子。

不难想到把节点状态改为:【目标棋子坐标】+【空位在目标棋子上下左右哪个方向】。这样状态数量就变成了 \(4nm\)。

那么如何转移状态?我们可以预处理一个 \(dist\) 数组 \(dist[a][b][c][d][e][f]\)

表示空位初始在 \((a,b)\),目标棋子在 \((c,d)\),空位要走到 \((e,f)\) 的最短路长度。

(在这里目标棋子没有什么用,仅仅看做一个障碍,空位不能移动到上面去)

这就有问题了:这样状态数不就又变成 \(O(n^3m^3)\) 了吗?

其实不然,我们发现由于上面已经进行了无效状态的去除,所以目标棋子一定会在初始空位的上下左右,这样状态数就又变成了 \(4n^2m^2\)。

预处理只要 bfs,复杂度与状态数相同,就是 \(O(n^2m^2)\)。

还有唯一一个问题:最初的时候空位并不一定在目标棋子四周。所以我们要强行把它移动过去——但我们怎么知道移动过去的代价呢?

其实我们调用 \(dist\) 数组就可以了,由于转移是双向的,可以看做从目标棋子四周移动到初始位置。

接着我们用 Dijkstra 跑出答案就可以啦!复杂度是 \(O(n^2m^2+Tnm \log (nm))\)

Code

使用这种方法要特判起点与终点相同的情况。

#include

#define debug(...) fprintf(stderr ,__VA_ARGS__)

#define __FILE(x)\

freopen(#x".in" ,"r" ,stdin);\</

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值