您的位置:首页 > 其它

POJ 3279 Fliptile(枚举状态)

2014-12-19 23:58 344 查看
题目链接:poj.org/problem?id=3279

题意:黑白的板,每次选择一个十字形翻转(十字板内黑白互换,若是边界则不管),求最小将原图变为全白的策略。

思路:如果第一行的翻转转态能够确定,那么就可以依次往下判断其他行是否需要翻转了,所以可以枚举第一行的状态,第一行翻转方式为2^N种,故时间复杂度为O(2 ^ N* M *N)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 30;

int dx[5] = { -1, 0, 0, 0, 1};
int dy[5] = {0, -1, 0, 1, 0};

int m, n;
int opt[maxn][maxn];
int flip[maxn][maxn];
int tile[maxn][maxn];

int get(int x, int y)
{
int c = tile[x][y];
for (int i = 0; i < 5; i++)
{
int nx = x + dx[i];
int ny = y + dy[i];
if (nx >= 0 && nx < m && ny >= 0 && ny < n)
c += flip[nx][ny];
}
return c % 2;
}

int cal()
{
for (int i = 1; i < m; i++)
for (int j = 0; j < n; j++)
{
if (get(i - 1, j))
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;
for (int i = 0; i < 1 << n; i++)
{
memset(flip, 0, sizeof(flip));
for (int j = 0; j < n; j++)
flip[0][n - 1 - j] = i >> j & 1;
int num = cal();
if (num >= 0 && (res < 0 || res > num))
{
res = num;
memcpy(opt, flip, sizeof(flip));
}
}
if (res < 0)
puts("IMPOSSIBLE");
else
{
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
printf("%d%c", opt[i][j], j == n - 1 ? '\n' : ' ');
}
}
}

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: