#include<stdio.h> #include<string.h> int map[16][16], dp[16][16], an[16][16]; int n, m, dx[4] = {0, 0, 1, -1}, dy[4] = {1, -1, 0, 0}; bool isflip(int x, int y) { int i, cnt = dp[x][y];//本来翻转的次数 for(i = 0; i < 4; ++i) { int nx = x+dx[i]; int ny = y+dy[i]; if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue; cnt += dp[nx][ny];//加上四周的点翻转的次数 } cnt += map[x][y];// 加上该点原来的状态 return cnt&1;//如果是奇数 则需要翻转 } int check() { int i, j; for(i = 1; i < n; ++i) for(j = 0; j < m; ++j) if(isflip(i-1, j))//是否需要翻转 dp[i][j] = 1; for(i = 0; i < m; ++i) if(isflip(n-1,i))//如果最后一行有1则失败 return -1; int ans = 0; for(i = 0; i < n; ++i) for(j = 0; j < m; ++j) ans += dp[i][j]; return ans; } int main() { int i, j, k; while(scanf("%d%d", &n, &m) != EOF) { for(i = 0; i < n; ++i) for(j = 0; j < m; ++j) scanf("%d", &map[i][j]); //枚举第一行的情况 int cas = 1 << m; int ans = 100000000; for(i = 0; i < cas; ++i)//每一个i代表第一行的一种翻转情况 { //对于每一个i进行暴力翻转 //如果最后一行全部翻转成功记录翻转的最小次数 //同时记录翻转后的状态 memset(dp, 0, sizeof(dp)); for(j = 0; j < m; ++j) if(i & (1<<j)) dp[0][j] = 1; int temp = check(); if(temp == -1) continue; else { if(temp < ans) { ans = temp; memcpy(an, dp, sizeof(dp)); } } } if(ans == 100000000) printf("IMPOSSIBLE\n"); else { for(i = 0; i < n; ++i) for(j = 0; j < m; ++j) { if(j != m-1) printf("%d ", an[i][j]); else printf("%d\n", an[i][j]); } } } return 0; }
题意:给出一个二维矩阵,每个点要么是0要么是1,现在对其中一个点进行翻转,那么这个点四周的点也会随之翻转,现在问最少翻转多少次能将该矩阵翻转为全0 的状态,如果不行则输出IMPOSSIBLE,若可以则输出每个点翻转的次数。
思路:对于二维的矩阵,我们列举第一行的所有情况,因为要求所有状态都为0, 所以当第一行状态确定时,第二行也就随之确定了,以此类推到最后一行,若最后一行状态全为0,则可以保存翻转的次数,若是比先前的小,则要保存当前每个点翻转的次数。最后输出结果。