题意:
n*m块区域,每一块有正反两面,两面分别是白色和黑色。
翻转一块区域的同时, 与其相邻的四块区域也会同时被反转
问最少需要翻转的次数 ,使所有的区域都变成白色 输出其翻转方案
思路:
枚举第一行的翻转状态
如果已经知道了第一行的状态,那么后面几行的状态就随之确定了——(如果该区域的上面一个区域是黑色,那这个区域必然是要反转才能让他上面的区域变成白色)
然后比较和记录最少的翻转次数 输出即可
code:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 20;
const int INF = 0x3f3f3f3f;
int maze[maxn][maxn], tmaze[maxn][maxn];
int ans[maxn][maxn], min_ans[maxn][maxn];
int n,m;
void deal(int x, int y){
tmaze[x][y] ^= 1;
tmaze[x+1][y] ^= 1;
tmaze[x-1][y] ^= 1;
tmaze[x][y+1] ^= 1;
tmaze[x][y-1] ^= 1;
}
void deal1(int s){
int cnt = m;
for(int i = 0; i < m; i++){
ans[1][cnt--] = (s>>i)&1;
}
}
bool deal2(){
for(int i = 1; i <= m; i++){
if(ans[1][i] == 1){
deal(1,i);
}
}
for(int i = 2; i <= n; i++){
for(int j = 1; j <= m; j++){
if(tmaze[i-1][j] == 1){
ans[i][j] = 1;
deal(i,j);
}
}
}
bool flag = true;
for(int i = 1; i <= m; i++){
if(tmaze[n][i] != 0){
flag = false;
}
}
return flag;
}
void init(){
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
scanf("%d",&maze[i][j]);
}
}
}
void solve(){
bool flag;
bool flag2 = false;
int min_ = INF;
memset(min_ans, 0, sizeof(min_ans));
for(int s = 0; s < (1<<m); s++){
memset(ans, 0, sizeof(ans));
memcpy(tmaze, maze, sizeof(maze));
deal1(s);//获取第一行状态 放到ans[1][i] 中
flag = deal2();//依据第一行进行翻转
if(flag){//成功 则输出
flag2 = true;
int tmp = 0;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(ans[i][j] == 1) tmp++;
}
}
if(tmp < min_){
memcpy(min_ans, ans, sizeof(ans));
min_ = tmp;
}
}
}
if(!flag2)
printf("IMPOSSIBLE\n");
else{
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(j != 1) printf(" ");
printf("%d",min_ans[i][j]);
}
printf("\n");
}
}
}
int main(){
scanf("%d%d",&n,&m);
init();
solve();
return 0;
}
虽然这道题目起码做过3回了,但还是不记得怎么做的....简直无情T_T比赛的时候没有出...被虐成马