Description:就不囉嗦了,見USACO的題目地址吧
http://ace.delos.com/usacoprob2?a=GYKcgnGbqEV&S=clocks
Analysis:
由於同一種方法轉4次相當於不轉,所以轉的方案數共有4^9種;
9個鐘的狀態也共有4^9種;
分別用1,2,3,0來表示3,6,9,12則最終狀態爲全0;
枚舉:分別枚舉9種方案的使用次數,然後判斷是否可行,下面的這個程序給我了很多啓發
Breadth First Search
這是我做的方法,一開始沒有用位運算來加速,所有就用了一個結構來保存,第一次用了結構內聲明函數來計算hash值;
位運算加速BFS
後來看了NOCOW上的位運算的思路,“
這樣,它們對應的二進制數爲:000,001,010,011。即,我們用三個位來記錄一個時鐘的狀態(爲什麼不用兩位?請思考)。
要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,因爲 << 的優先級比 +/- 低