题目:D - Fliptile
题意分析:
思路:利用二进制枚举第一行的所有状态
2
15
2^{15}
215当第一行翻转完后, 想要去掉第一行的1
, 需要翻转第二行对应列的位置
依次类推, 当第i
行确定时, 只有i+1
行对应列的位置翻转才会影响到i
相似题:费解的开关
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20;
const int INF = 0x3f3f3f3f;
int m, n;
int g[N][N], mp[N][N];
int res[N][N], rres[N][N];
void turn(int x, int y)
{
g[x][y] ^= 1;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
for(int i = 0; i < 4; i ++)
{
int tx = x + dx[i];
int ty = y + dy[i];
if(tx < 0 || ty < 0 || tx >= m || ty >= n) continue;
g[tx][ty] ^= 1;
}
}
int main()
{
cin >> m >> n;
for(int i = 0; i < m; i ++)
for(int j = 0; j < n; j ++)
cin >> g[i][j];
memcpy(mp, g, sizeof g);
int ans = INF;
for(int state = 0; state < 1 << n; state ++)
{
memset(res, 0, sizeof res);
int step = 0;
for(int j = 0; j < n; j ++)
{
if(state >> j & 1)
{
turn(0, n - j - 1);
res[0][n - j - 1] = 1;
step ++;
}
}
for(int i = 1; i < m; i ++)
{
for(int j = 0; j < n; j ++)
{
if(g[i - 1][j])
{
turn(i, j);
res[i][j] = 1;
step ++;
}
}
}
int flag = 0;
for(int j = 0; j < n; j ++)
if(g[m - 1][j])
{
flag = 1;
break;
}
memcpy(g, mp, sizeof g); // 不能放到最后
if(flag) continue;
if(ans > step)
{
ans = step;
memcpy(rres, res, sizeof res);
}
}
if(ans == INF)
cout << "IMPOSSIBLE" << endl;
else
{
for(int i = 0; i < m; i ++)
{
for(int j = 0; j < n; j ++)
cout << rres[i][j] << " ";
cout << endl;
}
}
}