看得我一脸懵逼。。。bfs感觉用不了,dfs又想不出来
查了一下发现所有的结果都和第一行有关(怎么想出来的orz)
所以枚举第一行所有情况
一堆二进制的操作只是优化
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int N = 16;
//输入的矩阵,复制出来做翻转的矩阵,储存被翻转的位置的矩阵
int g[ N ][ N ], t[ N ][ N ], f[ N ][ N ];
int cnt, n, m;
//四个方向
int x[ 4 ] = {0, 0, -1, 1};
int y[ 4 ] = {-1, 1, 0, 0};
void flip ( int i, int j ) {
++cnt, f[ i ][ j ] = 1; //步数++,记录翻转点
t[ i ][ j ] = !t[ i ][ j ]; //翻转自己
for ( int k = 0; k < 4; ++k )
if ( i + x[ k ] > -1 && j + y[ k ] > -1 )
t[ i + x[ k ] ][ j + y[ k ] ] ^= 1; //异或翻转
}
bool ok ( int k ) {
//初始化
cnt = 0;
memcpy ( t, g, sizeof ( t ) );
// 第一行的m列,
for ( int j = 0; j < m; ++j )
if ( k & ( 1 << ( m - 1 - j ) ) ) //找到k中翻转的列
flip ( 0, j );
for ( int i = 1; i < n; ++i ) // 把2--n行上面一行的1全翻成0
for ( int j = 0; j < m; ++j )
if ( t[ i - 1 ][ j ] )
flip ( i, j );
for ( int j = 0; j < m; j++ ) // 考察最后一行能不能翻成功
if ( t[ n - 1 ][ j ] )
return false;
return true;
}
int main () {
int ans, p;
while ( ~scanf ( "%d%d", &n, &m ) ) {
for ( int i = 0; i < n; ++i )
for ( int j = 0; j < m; ++j )
scanf ( "%d", &g[ i ][ j ] );
ans = n * m + 1, p = -1;
for ( int i = 0; i < ( 1 << m ); ++i ) // 枚举 2^m 种对第一行的翻转
if ( ok ( i ) && cnt < ans ) // 记录最小的翻转次数
ans = cnt, p = i;
memset ( f, 0, sizeof ( f ) );
if ( p >= 0 ) {
ok ( p );
for ( int i = 0; i < n; ++i )
for ( int j = 0; j < m; ++j )
printf ( "%d%c", f[ i ][ j ], j < m - 1 ? ' ' : '\n' );
} else
puts ( "IMPOSSIBLE" );
}
return 0;
}