题目连接: 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的循环快多了。调试