题意
给你一个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