上面有正经的题解,这里说一下优化方案。
这题从单向 BFS 的角度去考虑,不难发现每处理一组数据,整个解答数就要重新构造一遍。也就是不停的做重复工作。
那么不难想到,如果把解答数存下来,那么下次要用,就接着上一次的解答树往下走。
这个想法的好处就是,虽然比朴素的双向 BFS 在某个节点的数据量以下的速度慢一点,但是如果有大量的数据的话,速度可以降到常熟级别。
非常吸引人,对吧?
下面就说说具体的做法。
首先,既然起点有 9 种,那么我们就要 9 组队列,9 组 dist,9 组 vis,等等。
大致算法如下:
1)输入数据,处理出所有可能的 256 种末尾状态(具体见上面题解)
2)遍历这 256 种可能,如果有之前已经算过的,直接往“小于”的方向更新答案。
3)如果步骤 2)里成功更新了答案,输出。否则进入步骤 4)
4)从起点对应的队列开始搜,知道找到答案为止。途中记录下经过的点的相关数据。
这样以来,BFS 的最大计算量就是 9 * 9 *(6 ^ 8)= 136048896 次(貌似非常大啊!),然后复杂度骤减至常数 256。
下面直接看具体的代码把。
这个优化方法的问题就是,在一定的数据量以内,就是一个单纯的 BFS 算法(也许运气好,可以达到优化的效果)。
因此时间很长,总是 TLE。(尽管我已经尽可能的少用 STL 容器了,取而代之用数组)
那么为什么不能用双向 BFS 呢?
似乎也可以。
算法:
1)从头和尾分别开始搜索
2)如果搜到一块儿,输出
3)对于从头开始的那一支,记录沿途点到起点的距离。注意起点有 9 种可能,所以要分别记录。
4)下一次如果目标节点已经被对应起点的一支搜索过了,就直接输出。否则从对应起点剩余的队列和由新的终点开始的新的队列开始 BFS。
双向 BFS 可以把常数减半,非常好的办法。
真的吗?
不难发现,每次搜索中反向搜索的那一支的数据全部作废掉了,只有正向的才会记录数据。
(反向只记录路径上的点到终点的最短距离,但不能告诉我们从起点到这一点的最短距离,是吧?)
(假如起点为 S, 终点为 T。已知一个点 A 到 T 的最短距离和 S 到 T 的最短距离。问 S 到 A 的最短距离?显然不能直接减。事实上 SA + AT >= ST,这里指最短距离,不是字面上的意义。)
但是要想达到饱和量,正向搜索的次数是不会减少的。
因此得出结论:当我们用双向 BFS 处理数据时,在处理新的数据的时候时间可以减半,但是实际上记录的数据量也会减半。
这就导致了要想使记录的数据达到饱和,所需的时间要加倍。
时间加倍,正向搜索总量不变,那么时间就多花在了反向搜索的时间上面了,而且还是双倍的。(这里的时间是指记录量达到饱和所花的时间)
所以我说啊,对于小规模的数据,双向 BFS 可以很快搞定。然而如果要认真实现优化的话,还是用朴素的 BFS 好了。
差点忘了贴代码了。??
2018-01-28