今天看了poj1753,想了半天没有思路,就去看了一下题解《POJ 1753 Flip Game(状态压缩+BFS)解题报告》。这个题如果没之前没遇到过类型题的话,很难想到方法。先上题。
题目描述
如图,题目描述如下:
给定4*4的一个棋盘,并给定某一状态的黑白棋子状态和翻转规则,问最少经过多少步可以翻转到全黑或者全白?
翻转规则如下:
若选定一个坐标 (i,j) 的棋子进行翻转,那么该棋子邻边(上下左右)的棋子也一并会翻转(也就是共5个棋子进行了翻转)。黑色变白色,白色变黑色。
思路
主要讲一下解题思路,至于状态压缩的细节,以及如何进行位运算,作者blue的题解报告《POJ 1753 Flip Game(状态压缩+BFS)解题报告》已经介绍地很详细了,就不再重复造轮子了。
之所以一开始没有想到解题方法,是因为根本没有往bfs方向上想,因为如果进行状态遍历的话,时间复杂度是 $O(n^n)=O(16^{16})$,感觉会爆。不过看网上的题解说这个复杂度不大,囧,一看我就是小白。
- 首先将初始状态加入队列q; … (1)
- 若q不为空;则(3) …(2)
- 从队列中取出元素,依次翻转16个位置的棋子。如果翻转位置i的棋子之后,达到最终状态,则结束算法,返回步数。否则将该状态加入队列q,并翻转位置i+1,判断是否达到最终状态,直至遍历完16个位置。返回(2) …(3)
我咋感觉描述地这么晦涩。。。直接附上原作者代码吧。。明晚再ac替换代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| #include <cstdio> #include <queue> using namespace std;
const int size = 4; const int dir_num = 4; struct info { int value; int step; }; int dir[dir_num][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1}, }; int pos[size*size]; bool vis[1<<(size*size)];
bool Judge(int x, int y) { if(x>=0 && x<size && y>=0 && y<size) return true; else return false; }
void Initialize() { for(int i=0; i<size; ++i) { for(int j=0; j<size; ++j) { int value = 1 << (i*size + j); for(int k=0; k<dir_num; ++k) { int next_x = i+dir[k][0]; int next_y = j+dir[k][1]; if(Judge(next_x, next_y)) value += 1 << (next_x*size + next_y); } pos[i*size+j] = value; } } }
int BFS(int value) { queue<info> q; info s = {value, 0}; q.push(s); vis[s.value] = true; while(!q.empty()) { info f = q.front(); q.pop(); if(f.value==0 || f.value==(1<<(size*size))-1) return f.step; for(int i=0; i<size*size; ++i) { info next = {f.value^pos[i], f.step+1}; if(!vis[next.value]) { q.push(next); vis[next.value] = true; } } }
return -1; }
int main(int argc, char const *argv[]) { Initialize(); char str[5]; int value = 0; for(int i=0; i<size; ++i) { scanf("%s", str); for(int j=0; j<size; ++j) { if(str[j] == 'w') value += 1 << (i*size + j); } } int ans = BFS(value); if(ans >= 0) printf("%d\n", ans); else printf("Impossible\n"); return 0; }
|