本题知识点:深度优先搜索 + 暴力枚举 + 回溯
本题题意比较简单,要求把棋盘的棋子翻成同一颜色的,如果可以就输出最少步数,否则“Impossible”。
样例4步最快的就是把棋子都翻成white('w'),此时我犯了一个严重的错误。
在草稿纸上我的四步是这样走的:
第一步:翻 (1,1)
第二步:翻 (1,3)
第三步:翻 (2,2)
第四步:翻 (2,4)
// 1 2 3 4
// 1 b w w b
// 2 b b w b
// 3 b w w b
// 4 b w w w
于是我一整天的思路是:遍历16个点,然后每次遍历时重新从(1,1)这个点开始搜。
喵喵喵?那这样1s真的可以吗?
当然不行!
在花了一上午的时间后,我终于按耐不住看了其他大牛的题解,才发现自己以上的思路重复了。对!以上四步,无论哪步先走,效果都是一样的!
因此,我们只需要从 (1,1) 搜到 (4,4) 即可
搜的时候有两种状态,翻与不翻
例如:样例中, (1,1) 是翻了的,接着到 (2,2) 才翻,换句话说,(1,2) (1,3) (1,4) (2,1) 这些点都是没有翻的。
要注意的一点是,翻的棋子未必是正确的棋子,因此我们翻完之后还需要把它翻回原状(这就是回溯思想)
最后我们每次都查一下是否都是黑棋或者是白棋都行了。
(附上AC代码以及自己之前写的又长又臭的代码)
//// POJ 1753
#include<iostream>
#include<cstdio>
using namespace std;
char chess[10][10];
int ans = 0x3f3f3f3f, cnt;
void init(){
for(int i = 0; i < 10; i++){
for(int j = 0; j < 10; j++){
chess[i][j] = 'a';
}
}
}
bool check(){
bool can = true;
char ch = chess[1][1];
for(int i = 1; i <= 4; i++){
for(int j = 1; j <= 4; j++){
if(ch != chess[i][j]){
can = false;
return can;
}
}
}
return can;
}
void turn(int h, int w){
// mid
if(chess[h][w] == 'b') chess[h][w] = 'w';
else chess[h][w] = 'b';
// up
if(chess[h + 1][w] == 'b') chess[h + 1][w] = 'w';
else if(chess[h + 1][w] == 'w') chess[h + 1][w] = 'b';
// right
if(chess[h][w + 1] == 'b') chess[h][w + 1] = 'w';
else if(chess[h][w + 1] == 'w') chess[h][w + 1] = 'b';
// down
if(chess[h - 1][w] == 'b') chess[h - 1][w] = 'w';
else if(chess[h - 1][w] == 'w') chess[h - 1][w] = 'b';
// left
if(chess[h][w - 1] == 'b') chess[h][w - 1] = 'w';
else if(chess[h][w - 1] == 'w') chess[h][w - 1] = 'b';
}
void dfs(int h, int w, int cnt){
if(check()){ // check
if(cnt < ans) ans = cnt;
return ;
}
if(h == 5) return ;
// 翻它
turn(h, w); // change
if(w == 4) dfs(h + 1, 1, cnt + 1); // 换行
else dfs(h, w + 1, cnt + 1);
turn(h, w); // back 翻回来
// 不翻不翻
if(w == 4) dfs(h + 1, 1, cnt);
else dfs(h, w + 1, cnt);
}
int main()
{
init();
for(int i = 1; i <= 4; i++){
scanf("%s", chess[i] + 1);
}
dfs(1, 1, 0);
if(ans != 0x3f3f3f3f) printf("%d
", ans);
else printf("Impossible
");
return 0;
}
//#include<iostream>
//#include<cstdio>
//#include<cstring>
//using namespace std;
//
//char first[10][10];
//char chess[10][10];
//bool take[10][10];
//int ans = 0x3f3f3f3f, cnt;
//int black, white, B, W;
//
//void init(){
// for(int i = 0; i <= 5; i++){
// for(int j = 0; j <= 5; j++){
// first[i][j] = 'a';
// }
// }
//}
//
//void show(){
// for(int i = 1; i <= 4; i++){
// printf("%s
", chess[i] + 1);
//
// } putchar('
');
//}
//
//void save(){
// for(int i = 0; i <= 5; i++){
// for(int j = 0; j <= 5; j++){
// chess[i][j] = first[i][j];
// }
// }
//}
//
//bool check(){
// bool can = true;
// char ch = chess[1][1];
// for(int i = 1; i <= 4; i++){
// for(int j = 1; j <= 4; j++){
// if(ch != chess[i][j]){
// can = false;
// }
// }
// }
// return can;
//}
//
//void turn(int h, int w){
// // up
// if(chess[h + 1][w] == 'b') chess[h + 1][w] = 'w';
// else if(chess[h + 1][w] == 'w') chess[h + 1][w] = 'b';
// // right
// if(chess[h][w + 1] == 'b') chess[h][w + 1] = 'w';
// else if(chess[h][w + 1] == 'w') chess[h][w + 1] = 'b';
// // down
// if(chess[h - 1][w] == 'b') chess[h - 1][w] = 'w';
// else if(chess[h - 1][w] == 'w') chess[h - 1][w] = 'b';
// // left
// if(chess[h][w - 1] == 'b') chess[h][w - 1] = 'w';
// else if(chess[h][w - 1] == 'w') chess[h][w - 1] = 'b';
//}
//
//void back(int h, int w){
// // up
// if(chess[h + 1][w] == 'b') chess[h + 1][w] = 'w';
// else if(chess[h + 1][w] == 'w') chess[h + 1][w] = 'b';
// // right
// if(chess[h][w + 1] == 'b') chess[h][w + 1] = 'w';
// else if(chess[h][w + 1] == 'w') chess[h][w + 1] = 'b';
// // down
// if(chess[h - 1][w] == 'b') chess[h - 1][w] = 'w';
// else if(chess[h - 1][w] == 'w') chess[h - 1][w] = 'b';
// // left
// if(chess[h][w - 1] == 'b') chess[h][w - 1] = 'w';
// else if(chess[h][w - 1] == 'w') chess[h][w - 1] = 'b';
//}
//
//void solve_white(int h, int w){
// cnt++;
// // mid
// chess[h][w] = 'w';
// white++; black--;
// turn(h, w);
//
// if(check()){
// if(cnt < ans) ans = cnt;
//// show();
// return ;
// }
//
// for(int i = 1; i <= 4; i++){
// for(int j = 1; j <= 4; j++){
// if(chess[i][j] == 'b' && !take[i][j]){
// take[i][j] = true;
// solve_white(i, j);
// take[i][j] = false;
// cnt--;
// chess[i][j] = 'b';
// back(i, j);
// }
// }
// }
//}
//
//void solve_black(int h, int w){
// cnt++;
// // mid
// chess[h][w] = 'b';
// black++; white--;
// turn(h, w);
//
// if(check()){
// if(cnt < ans) ans = cnt;
//// show();
// return ;
// }
//
// for(int i = 1; i <= 4; i++){
// for(int j = 1; j <= 4; j++){
// if(chess[i][j] == 'w' && !take[i][j]){
// take[i][j] = true;
// solve_white(i, j);
// take[i][j] = false;
// cnt--;
// chess[i][j] = 'w';
// back(i, j);
// }
// }
// }
//}
//
//int main()
//{
// init();
// for(int i = 1; i <= 4; i++){
// scanf("%s", first[i] + 1);
// }
//
// save();
// if(check()){
// printf("%d
", 0);
// return 0;
// }
//
// // turn white is all
// for(int i = 1; i <= 4; i++){
// for(int j = 1; j <= 4; j++){
// if(chess[i][j] == 'b'){
// cnt = 0;
// black = B; white = W;
// take[i][j] = true;
// solve_white(i, j);
// memset(take, false, sizeof(take));
// save();
//// printf("i:%d j:%d ans:%d
", i, j, ans);
// }
// }
// }
// printf("white %d
", ans);
//
// save();
// memset(take, false, sizeof(take));
// // turn black is all
// for(int i = 1; i <= 4; i++){
// for(int j = 1; j <= 4; j++){
// if(chess[i][j] == 'w'){
// cnt = 0;
// black = B; white = W;
// take[i][j] = true;
// solve_black(i, j);
// memset(take, false, sizeof(take));
// save();
//// printf("i:%d j:%d ans:%d
", i, j, ans);
// }
// }
// }
//
// if(ans == 0x3f3f3f3f) printf("Impossible
");
// else printf("%d
", ans);
//
// return 0;
//}