poj3279 Fliptile

来源:互联网 发布:财新数据 编辑:程序博客网 时间:2024/05/29 17:29
#include <iostream>#include <cstring>using namespace std;// 邻接格子的坐标const int dx[5] = {-1, 0, 0, 0, 1};const int dy[5] = {0, -1, 0, 1, 0};const int MAX_M = 16;const int MAX_N = 16;int M, N;int tile[MAX_M][MAX_N];int opt[MAX_M][MAX_N]; // 保存最优解int flip [MAX_M][MAX_N]; // 保存中间结果// 查询(x, y)的颜色int get(int x, int y){int c = tile[x][y];for (int d = 0; d < 5; d++){int x2 = x + dx[d], y2 = y + dy[d];if (x2 >= 0 && x2 < M && y2 >= 0 && y2 < N){c += flip[x2][y2];}} return c % 2;}// 求出第1行确定情况下的最小操作次数int calc(){// 求出从第2行开始的翻转方法for (int i = 1; i < M; i++)for (int j = 0; j < N; j++){if (get(i - 1, j) != 0){// 如果同列的上一行为黑色,则必须翻转,因为此后,只有该点的翻转可以改变正上方的棋子颜色了flip[i][j] = 1; }}// 判断最后一行是否空白for (int j = 0; j < N; j++)if (get(M - 1, j)) // 无解 return -1;//统计翻转的次数int res = 0;for (int i = 0; i < M; i++)for (int j = 0; j < N; j++)res += flip[i][j];return res; }  void solve(){int res = -1;memset(opt, 0, sizeof(opt));// 按照字典序开始尝试第一行所有的可能性for (int i = 0; i < 1 << N; i++){memset(flip, 0, sizeof(flip)); // 每次必须重新清空flip for (int j = 0; j < N; j++){flip[0][N - 1 - j] = i >> j & 1;}int num = calc();if (num >= 0 && (res == -1 || res > num)){res = num;memcpy(opt, flip, sizeof(flip));}} if (res == -1) cout << "IMPOSSIBLE" << endl;else{for (int i = 0; i < M; i++){for (int j = 0; j < N - 1; j++)cout << opt[i][j] << " ";cout << opt[i][N - 1] << endl;}}}int main(){while (cin >> M >> N){for (int i = 0; i < M; i++)for (int j = 0; j < N; j++)cin >> tile[i][j];solve();}return 0;}

原创粉丝点击