在很多情况下,我们可以用一个整数或者多个整数把多变的状态压缩,这样有利于空间上的优化,虽然在代码量上并不能得到多少的好处,但是遇到数据量大的时候还是可以有一定的效果的。
以POJ1753为例,这题是推荐题中的简单题了,一般的搜索完全可以过,甚至不用搜索。。。
我的方法是把BFS的状态压缩,由于每个牌面就4乘以4,也就是16个格子,每个格子只有黑白两种状态,用一个int型数就可以装下整个状态。
将牌面从上到下从左到右编号0到15,这样int型数从低位开始的第i位标记为0或者1,分别表示白色和黑色,用位运算进行状态转移。
看下我的结构体:
code表示这个状态中各个格子是否被翻过,对应位如果为1,则表示被按过,这种题目有一个显著的特点,那就是一个格子之多翻一次,否则和没翻是一个效果,这样我们记录了格子后就可以知道哪些格子被我们翻过,那些没有。
table表示状态牌面的情况,第i位如果为1表示这位是黑色,否则为白色。
depth表示从初状态到此状态的步数。
last表示装移到这个状态翻转的格子编号,这样,我们每次都从最后一个翻转的格子之后的格子开始搜索,不会重复搜索。
另外,位压缩之后,写一个状态转移函数hash(),用于转移状态。
其中table参数就是需要变换的牌面,op代表翻转的格子的编号,函数中的st变量表示需要翻转的位,如果第i位需要翻转,则这位就是1,否则为0,首先第op位一定是需要翻转的,然后四个if判断格子的位置,当格子在最左边的时候,op%4等于0,最上边的时候,op/4等于0,以此类推,当格子不是最左边的时候,要对其左边(op-1)位置的格子进行翻转,因此更新st变量第(op-1)位为1,其他的类似。
在BFS函数中,末状态就是15个0或者16个0((1<<16)-1),这样直接用判断整数是否相等就可以搞定。
主程序完整代码如下:
反思:这题BFS位压缩其实还可以优化,code和last的作用是一样的,因为每次都从最后翻转的那位的后一位开始搜索,不用判断code变量,可以考虑将结构体变量再去掉一个。