#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,则可以保存翻转的次数,若是比先前的小,则要保存当前每个点翻转的次数。最后输出结果。