题意
给你一个01矩阵,矩阵大小为M x N。(1 <= M , N <= 15)
每次操作选择一个格子,使得该格子与上下左右四个格子的值翻转。 至少多少次操作可以使得矩阵中所有的值变为0?
请输出翻转方案,若没有方案,输出”IMPOSSIBLE”。
若有多种方案符合题意,请首先输出翻转次数最少的方案;若方案个数仍不唯一,则输出字典序最小的方案。
题解
枚举第一行的所有情况
从第二行开始到最后一行,如果当前格子的上一个行对应的格子为1,表示就要反转当前的格子
最后检验最后一行是否全为0
代码
#include <algorithm>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;
typedef long long ll;
int mp[30][30], tmp[30][30];
int n, m;
int dx[5] = {0, 0, 0, 0, -1};
int dy[5] = {0, 0, -1, 1, 0};//四个方向分别是自己,上,左,右
int pr[30][30];//答案数组
int work()
{
for (int i = 1; i < n; i++)
{
for (int j = 1; j <= m; j++)
{
int t = mp[i][j], cnt = 0;//t表示当前块是1还是0
for (int k = 1; k <= 4; k++)//前一行的四个方向
{
int x = i + dx[k];
int y = j + dy[k];
t += tmp[x][y];//如果本身是1,奇数次反转还是0,偶数次反转是1,本身是0反之
}
if (t & 1)//如果当前块是1
tmp[i+1][j] = 1;//下一行对应的块换为1保证当前为0
}
}
//检验最后一行是否为0
int i = n;
for (int j = 1; j <= m; j++)
{
int t = mp[i][j], cnt = 0;
for (int k = 1; k <= 4; k++)
{
int x = i + dx[k];
int y = j + dy[k];
t += tmp[x][y];
}
if (t & 1)//不合格就推出
return -1;
}
int ans = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (tmp[i][j] & 1)
ans++;
return ans;
}
int main()
{
// freopen("a.in","r",stdin);
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> mp[i][j];
int ans = 0x3f3f3f3f;
for (int i = 0; i < (1 << n); i++)
{
memset(tmp,0,sizeof(tmp));
for (int j = 0; j < m; j++)
tmp[1][j+1] = (i >> j) & 1;//枚举第一行的所有情况
int t = work();
if (t == -1)
continue;
if (ans > t){
ans =t;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
pr[i][j] = tmp[i][j];
}
}
if(ans==0x3f3f3f3f)
return cout<<"IMPOSSIBLE"<<endl,0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
cout << pr[i][j] << ' ';
cout << endl;
}
return 0;
}

thanks