要求:整齐摆放的m*n的瓦片有两面,分别为黑和白。0代表白,1代表黑。牛想要反转瓦片使所有的瓦片都是白色朝上。但是牛蹄过大使牛踩的瓦片连带上下左右共计五个瓦片都会反转。求最小反转次数满足要求,若有多解输出字典序最小的那个。
方法:dfs
1.每个瓦片要么翻1次,要么不翻。因为翻2次等于不翻。
2.每个瓦片的翻转次数确定了,那么反转次序无影响。
3.若第一行的n个瓦片的反转方案确定了,那么全部的反转方案就确定。逻辑是第i行的翻转方案确定后,若第i行第j列的瓦片是黑面朝上,那么第i+1行第j列的瓦片必须踩一次。
4.故需要暴力枚举第一行的翻转方案即可。
5.dfs枚举二进制数已经保证了字典序最小,故只注意题目要求翻砖次数需最少。
#include<iostream>
#include<stdio.h>
#include<queue>
#include<string.h>
#include<math.h>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std ;
int m , n ;
int num , tnum ;
int flip[20] ;
int map1[20][20] ;
int tmap1[20][20] ;
int ans[20][20] ;
int tans[20][20] ;
void output()
{
int i , j ;
for(i = 0 ; i < m ; i ++)
{
for(j = 0 ; j < n ; j ++)
printf("%d " , ans[i][j]) ;
printf("\n") ;
}
}
void fliptile(int i , int j)
{
tnum ++ ;
tmap1[i][j] = !tmap1[i][j] ;
if(i - 1 >= 0)
tmap1[i - 1][j] = !tmap1[i - 1][j] ;
if(i + 1 < m)
tmap1[i + 1][j] = !tmap1[i + 1][j] ;
if(j - 1 >= 0)
tmap1[i][j - 1] = !tmap1[i][j - 1] ;
if(j + 1 < n)
tmap1[i][j + 1] = !tmap1[i][j + 1] ;
}
bool judge()
{
int i , j ;
memcpy(tmap1 , map1 , sizeof(map1)) ;
for(i = 0 ; i < n ; i ++)
{
if(flip[i])
{
tans[0][i] = 1 ;
fliptile(0 , i) ;
}
else
tans[0][i] = 0 ;
}
for(i = 1 ; i < m ; i ++)
{
for(j = 0 ; j < n ; j ++)
{
if(tmap1[i-1][j])
{
tans[i][j] = 1 ;
fliptile(i , j) ;
}
else
tans[i][j] = 0 ;
}
}
for(i = 0 ; i < m ; i ++)
for(j = 0 ; j < n ; j ++)
if(tmap1[i][j])
return 0 ;
return 1 ;
}
void dfs(int k)
{
int i , j ;
if(k == n)
{
tnum = 0 ;
if(judge())
{
if(tnum < num)
{
num = tnum ;
memcpy(ans , tans , sizeof(tans)) ;
}
}
return ;
}
for(i = 0 ; i < 2 ; i ++)
{
flip[k] = i ;
dfs(k + 1) ;
}
}
int main()
{
int i , j ;
scanf("%d%d" , &m , &n) ;
for(i = 0 ; i < m ; i ++)
for(j = 0 ; j < n ; j ++)
scanf("%d" , &map1[i][j]) ;
num = inf ;
dfs(0) ;
if(num == inf)
printf("IMPOSSIBLE\n") ;
else
output() ;
}