题目
思路
首先看题目的话,这道题目其实可以归类到翻转问题里面,其实无论哪种情况,如果要是确定了第一行的状态,那么下面的翻转就全部确定了,此时,如果想将某一行的1全部翻转为0的话,只需要将1的下面的瓷砖翻转,轮到最后一行的时候,只要检查是否全为0就可以了,如果全为0则方案可行,否则的话此方案不可行,最后想要求出最少的翻转次数只要dfs就可以了,通过二进制枚举第一行的状态,要是字典序最小的话,第一行就从右往左填状态就可以了,注意同一块瓷砖翻转两次等于没有翻转。
题解
#include <iostream>
#include <cstring>
#include <stdio.h>
#include <algorithm>
using namespace std;
int xiang[5][2]={{0,0},{1,0},{-1,0},{0,-1},{0,1}};
int n,m;
int map[50][50],turn[50][50],ans[50][50];
int res,cnt;
int get_num(int x,int y)
{
int temp=map[x][y];
for(int i=0;i<5;i++)
{
int x_z=x+xiang[i][0];
int y_z=y+xiang[i][1];
if(x_z>=0&&x_z<n&&y_z>=0&&y_z<m)
{
temp+=turn[x_z][y_z];
}
}
return temp%2;
}
void dfs()
{
for(int i=1;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(get_num(i-1,j))
{
cnt++;
turn[i][j]=1;
}
if(cnt>res)
{
return;
}
}
}
for(int i=0;i<m;i++)
{
if(get_num(n-1,i))
{
return;
}
}
if(cnt<res)
{
res=cnt;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
ans[i][j]=turn[i][j];
}
}
}
}
int main()
{
res=10000000;
cin>>n>>m;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>map[i][j];
}
}
for(int i=0;i<(1<<m);i++)
{
cnt=0;
memset(turn,0,sizeof(turn));
for(int j=0;j<m;j++)
{
turn[0][m-j-1]=i>>j&1;
if(turn[0][m-j-1])
{
cnt++;
}
}
dfs();
}
if(res==10000000)
{
cout<<"IMPOSSIBLE"<<endl;
}
else
{
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cout<<ans[i][j]<<" ";
}
cout<<endl;
}
}
return 0;
}