題目連接: POJ -- 2965ios
題目給出的是4X4的矩陣,規模不算大。因爲問的是最少的操做步數,很容易想到bfs寬搜。一共16個格子,總共的狀態數是2^16,不算大,因此這個策略的確是對的。編程
可是須要注意到每一個「狀態」都是一個4x4的矩陣,咱們須要想辦法去記錄一個矩陣的狀態。用整數是一個直觀的方法,咱們每次對當前矩陣作過變形後,新的矩陣存儲於另外一個二維數組中,而後再算出表明新矩陣狀態的整數。我 們存儲這個整數就好。數組
可是這麼作是會超時的。緣由是這個寬搜的出度特別大,出度也是16(當前矩陣每改變一個元素都會生成一個新矩陣,一共16個元素)。加上咱們在矩陣和表明矩陣的整數之間作變換也須要消耗O(16)的時間,一共花掉了O(16^2)。一共2^16個狀態,咱們對每一個狀態作O(16^2)的操做,這個複雜度是大於10^7了,會超時。函數
解決的辦法是利用位運算。咱們將當前的矩陣用一個整數表明(和以前作的同樣),當對元素(i, j)做翻轉的時候,直接在整數上作文章就能完成(這個是能夠達到的,就是很麻煩),這樣不用在矩陣和整數之間來回轉,省下了O(16)的複雜度。優化
#include <cstdio> #include <iostream> #include <queue> using namespace std; typedef unsigned short ushort; char g[10][10]; int vis[100000], path[100000], from[100000]; ushort q[100000]; int front, end; ushort get_id(char g[10][10]) { ushort id = 0; for(int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) { id <<= 1; if(g[i][j] == '+') id |= 1; } } return id; } ushort black_mask_r[4] = { (((1 << 4) - 1) << (3*4)), (((1 << 4) - 1) << (2*4)), (((1 << 4) - 1) << (1*4)), ((1 << 4) - 1) }; ushort white_mask_r[4] = { ~(((1 << 4) - 1) << (3*4)), ~(((1 << 4) - 1) << (2*4)), ~(((1 << 4) - 1) << (1*4)), ~((1 << 4) - 1) }; ushort mark = (1 | (1 << 4) | (1 << 2*4) | (1 << 3*4)); ushort black_mask_c[4] = { (mark << 3), (mark << 2), (mark << 1), mark}; ushort white_mask_c[4] = { ~(mark << 3), ~(mark << 2), ~(mark << 1), ~mark}; ushort change_ij(ushort st, int i, int j) { ushort r = (st & black_mask_r[i]); r = ~r; r &= black_mask_r[i]; ushort restr = st & white_mask_r[i]; r = restr | r; ushort k = ((1 << (3-j)) << (4*(3-i))); r ^= k; ushort c = r & black_mask_c[j]; c = ~c; c &= black_mask_c[j]; ushort restc = r & white_mask_c[j]; c = restc | c; return c; } ushort id; void print_path(ushort st, int l) { if(from[st] < 0) { printf("%d\n", l); return ; } print_path(q[from[st]], l+1); printf("%d %d\n", path[st]/4+1, path[st]%4+1); } int main() { // freopen("in.txt", "r", stdin); for(int i = 0; i < 4; i++) { scanf("%s", g[i]); } id = get_id(g); vis[id] = 1; q[end++] = id; from[id] = -1; ushort ans = -1; while(front != end) { int index = front; ushort x = q[front++]; if(!x) { ans = x; break; } for(int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) { ushort st = change_ij(x, i, j); if(!vis[st]) { q[end++] = st; vis[st] = 1; path[st] = 4*i+j; from[st] = index; } } } } if(!ans) { print_path(0, 0); } return 0; }
位運算的代碼確實有點噁心,我編程能力差,調試了特別久。spa
代碼優化時間就是用change_ij函數去代替在矩陣數組和整數之間來回轉換,那個函數內部用的都是位運算,速度比4*4的循環快多了。調試