洛谷P5507 机关-双向bfs和启发式搜索

该博客详细介绍了如何使用双向BFS和启发式搜索解决洛谷P5507题目的过程。通过对比单向BFS的超时问题,提出双向BFS的优势,结合状态存储和状态转移的方法,进一步优化搜索过程。最后,引入A*算法,通过估计代价函数h(x)来加速搜索,确保找到最优解。
摘要由CSDN通过智能技术生成

更好的观看体验

题目链接 P5507 机关

题意简述

  有12个旋钮,每个旋钮开始时处于状态 1 1 1 ~ 4 4 4 ,每次操作可以往规定方向转动一个旋钮 ( 1 ⇒ 2 ⇒ 3 ⇒ 4 ⇒ 1 1\Rightarrow2\Rightarrow3\Rightarrow4\Rightarrow1 12341) ,并且会触发一次连锁反应:处于某个状态的旋钮在旋转时会引起另一个旋钮发生相同方向的转动(另一个旋钮转动不会再触发连锁反应)。问将12个旋钮都置为 1 1 1 至少需要几次转动,并输出每次转动的旋钮编号。

单向BFS

  直接暴力地进行单向 B F S \mathrm{BFS} BFS ,每次转动都有 12 12 12 种选择,时间复杂度是 O ( 1 2 s t e p ) O(12^{step}) O(12step) ,看数据范围,最高的步数可达 17 17 17 步,必定 T L E \mathrm{TLE} TLE 。但是这样简单如果优化的比较好可以得 50 50 50 ~ 60 60 60 分(没吸氧气,吸了氧气反而更低了)。
  单向BFS评测记录
  超时的主要原因是搜索树过于庞大,而我们会发现本题起始状态和终止状态是明确的,这时我们就可以使用神奇的双向 B F S \mathrm{BFS} BFS 来限制搜索树的生长。

双向BFS

  双向 B F S \mathrm{BFS} BFS 非常适合在起始状态和终止状态明确的条件下使用,做法是从起点和终点同时进行单向 B F S \mathrm{BFS} BFS ,让两边 B F S \mathrm{BFS} BFS 搜索树的生长受到对面搜索树的限制,不要过于野蛮生长,偏离目标太远。自己画了一张很丑很丑的对比图,应该可以便于理解。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VaMYqi3o-1609721541210)(https://images.cnblogs.com/cnblogs_com/ailanxier/1827981/o_200814043631%E5%AF%B9%E6%AF%94.jpg)]
  可以看到双向 B F S \mathrm{BFS} BFS 可以在某一状态发现相同时就停止了,通过回溯可以找到沿路选择的点。再看看本题的数据范围,最大的点正向和反向 B F S \mathrm{BFS} BFS 最多是 9 9 9 步, 1 2 9 12^9 129 5 × 1 0 8 5\times10^8 5×108 的量级,勉强可以在一秒冲过去。事实上我最大的点用时在 200 m s 200ms 200ms ~ 300 m s 300ms 300ms 之间,还是很稳的。
最好的一次双向BFS记录

状态存储

  可以把两个二进制位当做一个四进制位,把每个旋钮状态减一后就刚好可以存下了,即1对应0,2对应1,以此类推。先讲一下读入处理。

int button,Start = 0;
For(i,0,11){
   
    button = read();                        //读入第i+1个旋钮状态
    Start |= (button - 1) << (i << 1);      //记录初始状态
    For(j,0,3) nxt[i][j] = read()-1;          
}

  我代码中的旋钮编号和状态全部进行了减一处理(后面描述时我都会说+1),方便位运算操作。注意记录初始状态时要将 i ∗ 2 i*2 i2 (即左移一位),因为我们把两个二进制位当做一个四进制位了,后面也有这样的乘2处理。再用一个数组 n x t nxt nxt 记录第 i + 1 i+1 i+1 个旋钮在 j + 1 j+1 j+1 状态下进行旋转时,会带动第 n x t [ i ] [ j ] + 1 nxt[i][j]+1 nxt[i][j]+1 个旋钮转动。

状态转移

  首先正向和反向的 B F S \mathrm{BFS} BFS 的转移方式是不一样的。设当前转到的是第 i + 1 i+1 i+1 个旋钮,它现在处于 j + 1 j+1 j+1 状态。

  • 正向:将第 i + 1 i+1 i+1 个旋钮按规定方向转动一次,同时带动第 n x t [ i ] [ j ] + 1 nxt[i][j]+1 nxt[i][j]+1 个旋钮转动。旋转后状态可以用 ( j + 1 ) & 3 (j+1)\&3 (j+1)&3 表示(这样可以实现旋钮位于4状态,即 j = 3 j=3 j=3 时,旋转后变成1 ,即 j = 0 j = 0 j=0 的操作)。
  • 反向:将第 i + 1 i+1 i+
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ailanxier

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值