题目大意:给定一个矩阵,要么黑要么白,求出按照规则将其翻转为全白最小翻转次数的方案,如有多种最小方案则输出字典序最小的方案
分析:此题为经典的翻转问题(开关问题),在看此题解析之前,希望大家看看我这篇文章:点击打开链接
附上代码:
#include<cstdio> #include<cstring> using namespace std; #define INF 0x3f3f3f3f bool a[20][20]; //存图 bool b[20][20]; //保存当前翻转方案 bool c[20][20]; //保存最优解 int d[5][2] = { { -1, 0 }, { 1, 0 }, { 0, 0 }, { 0, -1 }, { 0, 1 } }; int ans = INF; int n, m; bool getcolor(int x, int y) //得到x,y的颜色 { int res = a[x][y]; for (int i = 0; i < 5; i++) { int fx = x + d[i][0], fy = y + d[i][1]; if (fx >= 1 && fx <= n && fy >= 1 && fy <= m) res += b[fx][fy]; } return res % 2; } int solve() { int res = 0; for (int i = 2; i <= n; i++) //从第二行开始检查是否需要翻转 for (int j = 1; j <= m; j++) if (getcolor(i - 1, j)) b[i][j] = 1; for (int i = 1; i <= m; i++) //检查最后一行是否全为白色 if (getcolor(n, i)) return INF; for (int i = 1; i <= n; i++) //统计翻转次数 for (int j = 1; j <= m; j++) res += b[i][j]; return res; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) scanf("%d", &a[i][j]); for (int s = 0; s < 1 << m; s++) //按照字典序枚举第一行所以翻转可能 { memset(b, false, sizeof b); for (int i = 1; i <= m; i++) b[1][i] = s >> (m - i) & 1; int t = solve(); if (t < ans) { ans = t; memcpy(c, b, sizeof b); } } if (ans == INF) printf("IMPOSSIBLE\n"); else { for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) printf("%d ", c[i][j]); printf("\n"); } } return 0; }