UVa 1604 Eight Cubic-Puzzle 优化方案

Posted alrond

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVa 1604 Eight Cubic-Puzzle 优化方案相关的知识,希望对你有一定的参考价值。

上面有正经的题解,这里说一下优化方案。

这题从单向 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

以上是关于UVa 1604 Eight Cubic-Puzzle 优化方案的主要内容,如果未能解决你的问题,请参考以下文章

UVa 1604 Eight Cubic-Puzzle 优化方案

习题 7-9 UVA-1604Cubic Eight-Puzzle

HDU 1043 Eight BFS

HDU - 3567 Eight II IDA*

HDU 2514 Another Eight Puzzle(DFS)

CPP-week eight