本題知識點:深度優先搜索 + 暴力枚舉 + 回溯
本題題意比較簡單,要求把棋盤的棋子翻成同一顏色的,如果可以就輸出最少步數,否則“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\n", ans);
else printf("Impossible\n");
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\n", chess[i] + 1);
//
// } putchar('\n');
//}
//
//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\n", 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\n", i, j, ans);
// }
// }
// }
// printf("white %d\n", 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\n", i, j, ans);
// }
// }
// }
//
// if(ans == 0x3f3f3f3f) printf("Impossible\n");
// else printf("%d\n", ans);
//
// return 0;
//}