个人感觉这道题有点像是广搜和枚举的结合体。
大体的思路是这样的:
- 把初始棋盘加入队列里
- 判定队列首项是不是满足条件,满足条件输出对应步数;
- 队列首项每个位置逐个枚举下一步的状态,如果没出现过则加入队列;
- 步骤2-3循环,直至队列为空,则说明不可能。
#include <iostream>
#include <queue>
#include <cmath>
using namespace std;
class board {
int b;
int move;
int getBinary(int bit) {
return 1 << bit;
}
void flip(int x, int y) {
b = b ^ getBinary(y * 4 + x);
}
public: void setMove(int val) {
move = val;
}
public: int getMove() {
return move;
}
public: int toDecimal() {
return b;
}
public: void flipChess(int x, int y) {
flip(x, y);
if (x > 0) flip(x - 1, y);
if (x < 3) flip(x + 1, y);
if (y > 0) flip(x, y - 1);
if (y < 3) flip(x, y + 1);
}
public: void setChess(int x, int y, bool val) {
int base = y * 4 + x;
int binary = getBinary(base);
b = ((b & binary) == 0) == val ? val ? b += binary : b-= binary : b;
}
public: bool validate() {
return b == 0 || b == 65535;
}
};
int main(int argc, const char * argv[]) {
board init;
queue<board> search;
bool board_record[65536] = {false};
string input;
for (int i = 0; i < 4; i++) {
cin >> input;
for (int j = 0; j < 4; j++) {
init.setChess(j, i, input[j] == 'b');
}
}
init.setMove(0);
search.push(init);
board_record[init.toDecimal()] = true;
while (!search.empty()) {
board curr = search.front();
if (curr.validate()) {
cout << curr.getMove();
return 0;
}
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
board new_board = curr;
new_board.flipChess(x, y);
new_board.setMove(curr.getMove() + 1);
int base = new_board.toDecimal();
if (!board_record[base]) {
search.push(new_board);
board_record[base] = true;
}
}
}
search.pop();
}
cout << "Impossible";
return 0;
}
最开始用了一个bool数组b[16]记录棋盘状态,结果TLE了。
于是改成了用一个int b记录棋盘状态:二进制下2^i对应之前的b[i],于是就AC了。
还有很多可以优化的空间,不过既然AC了就先水过了吧~