版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39562952/article/details/82813250
思路:
翻转偶数次跟翻转0次是一样的,奇数次是跟1次是一样的,所以最后的结果中只可能有0,1;
下一行的状态可以通过前二行的的状态得到,因为在求(i,j)是否要翻转的时候,(i-1,j)(i-1,j-1)(i-1,j+1)(i-2)(j)是否翻转都已经知道了,并且要(i-1,j)这个位置是0,那么就可以推出(i,j)这个位置是否要翻转,所以其实问题中只要枚举第一行的所有情况,就能推出所有的情况,并且一共最多只有2^15种;
枚举方法要保证最后的答案是字典序最小的,那么可以用二进制来表示每一位的状态(0----2^n),第i种情况下,第j个位置的值应该是i>>j&1(不明白的可以自己推导一下),如果答案是1那么就说明要进行翻转,如果是0,就不用;
代码如下:
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <cstring>
#include <climits>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stdio.h>
#define esp 1e-4
using namespace std;
int ini[20][20];
int flip[20][20];
int final_ans[20][20];
int m,n;
int main()
{
while(cin>>m>>n)
{
int ans=1e8;
int time=0;//要翻转的次数
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
cin>>ini[i][j];
}
}
int ok=0;
for(int i=0;i<(1<<n);i++)
{
memset(flip,0,sizeof(flip));
for(int j=1;j<=n;j++)
{
flip[1][j]=i>>(j-1) &1;
if(flip[1][j])
time++;
}
for(int r=2;r<=m;r++)
{
for(int c=1;c<=n;c++)
{
if((ini[r-1][c]+flip[r-1][c]+flip[r-1][c-1]+flip[r-1][c+1]+flip[r-2][c])&1)
{
flip[r][c]=1;
time++;
}
}
}
int flag=1;
for(int j=1;j<=n;j++)
{
if((ini[m][j]+flip[m][j]+flip[m-1][j]+flip[m][j-1]+flip[m][j+1])&1)
{
flag=0;
break;
}
}
if(flag && time<ans)
{
ok=1;
ans=time;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
final_ans[i][j]=flip[i][j];
}
}
}
}
if(ok)
{
for(int i=1;i<=m;i++)
{
cout<<final_ans[i][1];
for(int j=2;j<=n;j++)
{
cout<<" "<<final_ans[i][j];
}
cout<<endl;
}
}
else
cout<<"IMPOSSIBLE\n";
}
return 0;
}