在很多情況下,我們可以用一個整數或者多個整數把多變的狀態壓縮,這樣有利於空間上的最佳化,雖然在代碼量上並不能得到多少的好處,但是遇到資料量大的時候還是可以有一定的效果的。
以POJ1753為例,這題是推薦題中的簡單題了,一般的搜尋完全可以過,甚至不用搜尋。。。
我的方法是把BFS的狀態壓縮,由於每個牌面就4乘以4,也就是16個格子,每個格子只有黑白兩種狀態,用一個int型數就可以裝下整個狀態。
將牌面從上到下從左至右編號0到15,這樣int型數從低位開始的第i位標記為0或者1,分別表示白色和黑色,用位元運算進行狀態轉移。
看下我的結構體:
struct Node<br />{<br />int code;<br />int table;<br />int depth;<br />int last;<br />}start;
code表示這個狀態中各個格子是否被翻過,對應位如果為1,則表示被按過,這種題目有一個顯著的特點,那就是一個格子之多翻一次,否則和沒翻是一個效果,這樣我們記錄了格子後就可以知道哪些格子被我們翻過,那些沒有。
table表示狀態牌面的情況,第i位如果為1表示這位是黑色,否則為白色。
depth表示從初狀態到此狀態的步數。
last表示裝移到這個狀態翻轉的格子編號,這樣,我們每次都從最後一個翻轉的格子之後的格子開始搜尋,不會重複搜尋。
另外,位壓縮之後,寫一個狀態轉移函數hash(),用於轉移狀態。
int hash(int table,int op)<br />{<br />int st;</p><p>st=(1<<op);<br />if(op%4>0)<br />st|=(1<<(op-1));<br />if(op%4<3)<br />st|=(1<<(op+1));<br />if(op/4>0)<br />st|=(1<<(op-4));<br />if(op/4<3)<br />st|=(1<<(op+4));</p><p>return (table^st);<br />}
其中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),這樣直接用判斷整數是否相等就可以搞定。
主程式完整代碼如下:
#include <iostream><br />#include <cstring><br />#include <cstdlib><br />#include <cstdio><br />#include <queue></p><p>using namespace std;</p><p>struct Node<br />{<br />int code;<br />int table;<br />int depth;<br />int last;<br />}start;</p><p>int hash(int table,int op)<br />{<br />int st;</p><p>st=(1<<op);<br />if(op%4>0)<br />st|=(1<<(op-1));<br />if(op%4<3)<br />st|=(1<<(op+1));<br />if(op/4>0)<br />st|=(1<<(op-4));<br />if(op/4<3)<br />st|=(1<<(op+4));</p><p>return (table^st);<br />}</p><p>int bfs()<br />{<br />Node node,next;<br />queue<Node> q;</p><p>node.code=0;<br />node.table=start.table;<br />node.depth=0;<br />node.last=-1;<br />if(node.table==0||node.table==((1<<16)-1))<br />return 0;<br />q.push(node);<br />while(!q.empty())<br />{<br />node=q.front();<br />q.pop();<br />for(int i=node.last+1;i<16;i++)<br />{<br />if((node.code&(1<<i))==0)<br />{<br />next.code=(node.code|(1<<i));<br />next.table=hash(node.table,i);<br />next.depth=node.depth+1;<br />next.last=i;<br />if(next.table==0||next.table==((1<<16)-1))<br />return next.depth;<br />q.push(next);<br />}<br />}<br />}</p><p>return -1;<br />}</p><p>int main()<br />{<br />char str[10];</p><p>start.table=0;<br />for(int i=0;i<4;i++)<br />{<br />gets(str);<br />for(int j=0;j<4;j++)<br />{<br />if(str[j]=='b')<br />{<br />start.table|=(1<<(i*4+j));<br />}<br />}<br />}</p><p>int ret=bfs();<br />if(ret==-1)<br />printf("Impossible/n");<br />else<br />printf("%d/n",ret);</p><p>return 0;<br />}<br />
反思:這題BFS位壓縮其實還可以最佳化,code和last的作用是一樣的,因為每次都從最後翻轉的那位的後一位開始搜尋,不用判斷code變數,可以考慮將結構體變數再去掉一個。