網上題解很多了。
枚舉第一行情況,然後遍歷2至n行:若上一個元爲“1”,則翻轉當前元(因爲只有這樣才能改變上一元)。
最後檢驗最後一行是否全零。
#include <iostream>
#include <cstdio>
#include <cstring>
const int MAX = 15;
using namespace std;
int n;
int m;
int ans;
int step;
bool loc[MAX+2][MAX+2];
bool temp_loc[MAX+2][MAX+2];
bool tile[MAX+2][MAX+2];
bool temp_tile[MAX+2][MAX+2];
void read_tile()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%d", &tile[i][j]);
}
const int ROW[] = {0, 0, 0, 1, -1};
const int COL[] = {0, 1, -1, 0, 0};
void _flip(int r, int c)
{
for (int i = 0; i < 5; i++)
temp_tile[r+ROW[i]][c+COL[i]] = !temp_tile[r+ROW[i]][c+COL[i]];
}
void _enumberate(int ord)
{
for (int j = 1; j <= m; j++)
{
if (ord & 1)
{
_flip(1, j);
temp_loc[1][j] = true;
step++;
}
ord >>= 1;
}
}
void _operate()
{
for (int i = 2; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (temp_tile[i-1][j])
{
_flip(i, j);
temp_loc[i][j] = true;
step++;
}
}
}
}
bool is_ok()
{
for (int j = 1; j <= m; j++)
if (temp_tile[n][j])
return false;
return true;
}
bool lesser(bool temp_loc[][MAX+2], bool loc[][MAX+2])
{
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (temp_loc[i][j] == loc[i][j])
continue;
return (temp_loc[i][j] < loc[i][j]);
}
return false;
}
void _print(bool mark)
{
if (mark)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
printf("%d ", loc[i][j]);
putchar('\n');
}
}
else
printf("IMPOSSIBLE");
}
int main()
{
// input
read_tile();
// work
int sz;
bool mark = false;
sz = 1 << m;
ans = MAX * MAX;
for (int i = 0; i < sz; i++)
{
step = 0;
memset(temp_loc, 0, sizeof(temp_loc));
memcpy(temp_tile, tile, sizeof(tile));
_enumberate(i);
_operate();
if(is_ok())
{
mark = true;
if (step < ans)
{
ans = step;
memcpy(loc, temp_loc, sizeof(temp_loc));
}
else if (step == ans && lesser(temp_loc, loc))
{
memcpy(loc, temp_loc, sizeof(temp_loc));
}
}
}
_print(mark);
return 0;
}