题目大意
进阶题
题目链接
翻转游戏是在一个矩形的4x4场上进行的,在其16个正方形的每个正方形上放置了两个双面棋子。 每一块的一侧为白色,另一侧为黑色,并且每一块都以黑色或白色的一面朝上。 每轮翻转3到5片,从而将其上侧的颜色从黑色更改为白色,反之亦然。 根据以下规则,每轮选择要翻转的棋子:
选择16件中的任何一件。
将选定的片段以及所有相邻片段翻转到选定片段的左侧,右侧,顶部和底部(如果有)。
求最小的翻转次数,既可以反转成全白,也可以全黑。
思路分析
典型的反转问题,和这道题非常类似。看到好像有人用dfs做,肯定也是可以的,毕竟4*4,但是这道进阶题就不行了,反转问题尽量还是状态压缩吧。我们需要对全黑和全白分开计算,先确定第一行的翻转方式,第二行是否反转取决于上一行的对应元素是黑还是白。
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<string.h>
using namespace std;
#define MAX 16
int flip[4][4];//记录每个位置反转了几次
int arr[4][4], res = 10000000;//初始数组,结果值
int dx[5] = { 0,0,0,1,-1 }, dy[5] = { 0,1,-1,0,0 };
int getCnt(int x, int y) {
//统计(x,y)的上下左右位置一共的翻转次数和本身的情况
int sum = arr[x][y];
for (int i = 0; i < 5; i++) {
int xx = x + dx[i], yy = y + dy[i];
if (xx >= 0 && xx < 4 && yy >= 0 && yy < 4) sum += flip[xx][yy];
}
return sum;
}
int main() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
char s; cin >> s;
if (s == 'b')arr[i][j] = 0;
else arr[i][j] = 1;
}
}
//1:测试全部反转到0的最小步数:
for (int i = 0; i < 15; i++) {//第一行的翻转方式:注意不是状态而是如何翻转
int step = 0;
memset(flip, 0, sizeof(flip));
for (int j = 0; j < 4; j++) {//统计第一行的翻转信息
flip[0][j] = (i >> j) & 1;//i>>j就取出了i的第j位,如果是1表示这里反转一次
step += flip[0][j];
}
for (int m = 1; m < 4; m++) {
for (int n = 0; n < 4; n++) {
int sum = getCnt(m - 1, n);//这一行是否翻转取决于上一行的对应元素
if (sum % 2 == 1) { flip[m][n] += 1; step++; }
}
}
int m = 0;
for (m = 0; m < 4; m++) {//判断最后一行是否满足要求
if (getCnt(3, m) % 2 != 0)break;
}
if (m == 4) { res = min(res, step); }
}
//2:测试全部反转到1的最小步数:
for (int i = 0; i < 15; i++) {//第一行的翻转方式:注意不是状态而是如何翻转
int step = 0;
memset(flip, 0, sizeof(flip));
for (int j = 0; j < 4; j++) {//统计第一行的翻转信息
flip[0][j] = (i >> j) & 1;//i>>j就取出了i的第j位,如果是1表示这里反转一次
step += flip[0][j];
}
for (int m = 1; m < 4; m++) {
for (int n = 0; n < 4; n++) {
int sum = getCnt(m - 1, n);//这一行是否翻转取决于上一行的对应元素
if (sum % 2 == 0) { flip[m][n] += 1; step++; }
}
}
int m = 0;
for (m = 0; m < 4; m++) {//判断最后一行是否满足要求
if (getCnt(3, m) % 2 == 0)break;
}
if (m == 4) { res = min(res, step); }
}
if (res != 10000000)cout << res << endl;
else cout << "Impossible" << endl;
}