USACO 1.4 clocks 分析

Description就不啰嗦了,见USACO的题目地址吧

http://ace.delos.com/usacoprob2?a=GYKcgnGbqEV&S=clocks

Analysis

由于同一种方法转4次相当于不转,所以转的方案数共有4^9种;

9个钟的状态也共有4^9种;

分别用1230来表示36912则最终状态为全0

 

枚举:分别枚举9种方案的使用次数,然后判断是否可行,下面的这个程序给我了很多启发

 

Breadth First Search

这是我做的方法,一开始没有用位运算来加速,所有就用了一个结构来保存,第一次用了结构内声明函数来计算hash值;

  

位运算加速BFS

后来看了NOCOW上的位运算的思路,“

这样,它们对应的二进制数为:000001010011。即,我们用三个位来记录一个时钟的状态(为什么不用两位?请思考)。

 

tick一个时钟的时候,就给该位加上一,再用按位与的方法去除高位的1

 

令最高的三位为时钟A,最低的三位为时钟I,那么:

 

数“57521883”用于清除每个时钟状态最高位的一(按位与)。

 

const long move[9] = {18911232, 19136512, 2363904, 16810048, 2134536, 262657, 36936, 73, 4617}

 

move[i]表示题述中的第i+1种方法

 

f[q]为原状态,比如用题述中的第k种方法,那么可以写成 f[q + 1] = (f[q] + move[k - 1]) & 57521883;

 

9个时钟都回归12点的时候,巧的是状态f=0。这样,判断每个状态f是否为0,就知道是否求出可行解。

上述方法要想用C++的程序过是不太可行的(除非你用要麻烦一下,把一个数拆成9个去hash,但这样就体现不出位运算的优势了),因为要开一个57521883大的BOOL数组,但在C++中空间分配至少是1个字节,BOOL的前7位是无用的0,所以大小达到了57521883/2^20 M = 54 M,如果能用1位来存贮,则使用54 / 8 M = 6.75 M,由于USACO评测系统给的内存只有16 M,所以就不行了,但用自己电脑测试还是可以的,速度比前一种方法快10%左右。

还要特别注意的是:<<+的优先级,比如 1 << 2 + 3 = ?,不是7,而是32,因为 << 的优先级比 +/-

还有一种很强的数学方法,和解方程法;

猜你喜欢

转载自blog.csdn.net/zjsxzjb/article/details/6173389
1.4