枚举第一行的翻转所有翻转情况然后逐行向下更新,如果上一行是1的话,那么下面一行肯定要翻转,因为只有下面一行能影响上面一行。
最后判断一下,最后一行是不是都是0,如果都是,则维护最小的翻转次数。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<vector>
#include<map>
#define INF 1<<30
using namespace std;
int m,n,res;
int tmp[20][20],a[20][20],b[20][20],aa[20][20];
int judge()
{
int i;
for(i=0; i<n; i++)
if(b[m-1][i])
return 0;
return 1;
}
void filp(int x,int y)
{
int next[5][2]= {{0,0},{0,1},{0,-1},{-1,0},{1,0}};
int k,tx,ty;
tmp[x][y]=1;
for(k=0; k<5; k++)
{
tx=next[k][0]+x;
ty=next[k][1]+y;
if(tx<0||ty<0||tx>m-1||ty>n-1)
continue;
b[tx][ty]=!b[tx][ty];
}
}
void sove(int t)
{
memcpy(b,a,sizeof(a));
memset(tmp,0,sizeof(tmp));
int ans=0,i,j;
for(i=0; i<n; i++)
if((t>>i)&1)
{
filp(0,i);
ans++;
}
for(i=1; i<m; i++)
for(j=0; j<n; j++)
if(b[i-1][j])
{
filp(i,j);
ans++;
}
if(judge()&&ans<res)
{
memcpy(aa,tmp,sizeof(tmp));
res=ans;
}
}
int main()
{
int i,j;
while(~scanf("%d%d",&m,&n))
{
memset(a,0,sizeof(a));
for(i=0; i<m; i++)
for(j=0; j<n; j++)
scanf("%d",&a[i][j]);
int k=1<<n;
res=INF;
for(i=0; i<=k; i++)
sove(i);
if(res==INF)
printf("IMPOSSIBLE\n");
else
{
for(i=0; i<m; i++)
for(j=0; j<n; j++)
printf("%d%c",aa[i][j],j==n-1?'\n':' ');
}
}
return 0;
}