黑白翻转的问题,值得借鉴的是:
1.使用左移+按位与运算的方法保留二进制相应位置的数字
2.memcpy函数的使用,用于数组的复制
3.使用0x3f3f3f3f表示无穷大
#include<iostream>
#include<cstring>
#include<string>//数组复制函数
using namespace std;
int mapp[20][20];//初始数组
int cal[20][20];//每个位置是否翻转的数组
int opt[20][20];//最终结果
int n,m;//n行m列
int dir[5][2]= {{0,0},{0,1},{0,-1},{1,0},{-1,0}};
bool judge(int x,int y)
{
if(x<1||x>n||y<1||y>m)
return false;
else
return true;
}
int func(int x,int y)//判断是否为黑色,是返回1
{
//(x,y)位置的状态由初始状态+它本身+周围4个位置的翻转状态得到
int res=mapp[x][y];
for(int i=0; i<5; i++)
{
int xx=x+dir[i][0];
int yy=y+dir[i][1];
if(judge(xx,yy))//判断位置是否合法
{
res+=cal[xx][yy];
}
}
return res%2;
}
int dfs()
{
for(int i=2; i<=n; i++)
for(int j=1; j<=m; j++)
if(func(i-1,j))//如果(i-1,j)位置为黑色,cal[i][j]必须翻转
cal[i][j]=1;
//按照这个规则翻转到最后一行,检查最后一行是不是都为白色
for(int i=1; i<=m; i++)
if(func(n,i))//一旦出现黑色的位置
return -1;//翻转失败
int res=0;//记录结果次数
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
res+=cal[i][j];
return res;
}
int main()
{
//这种对行数和列数要求高的矩阵,直接用i表示行,j表示列
cin>>n>>m;
int ans=0x3f3f3f3f;//大体表示无穷,2^9
int flag=0;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
cin>>mapp[i][j];
//枚举第一行翻转和不翻转的所有情况
for(int i=0; i<1<<m; i++) //i表示的时1到(2^m-1)这m个数字
{
memset(cal,0,sizeof(cal));//枚举2^m种情况,寻找最优解
for(int j=1; j<=m; j++)
{
cal[1][j]=i>>(m-j)&1;
}//(1,j)坐标位置记录i相应位置的二进制数字
//这个方法值得借鉴,用【左移之后按位与1】的方法记录相应位置的二进制数字
int temp=dfs();
if(temp>=0&&temp<ans)//最小次数
{
ans=temp;
memcpy(opt,cal,sizeof(cal));//数组复制函数
flag=1;
}
}
if(flag)
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
if(j!=1)
cout<<" ";
cout<<opt[i][j];
}
cout<<endl;
}
}
else
cout<<"IMPOSSIBLE"<<endl;
return 0;
}