POJ 3279 Fliptile(枚举状态)

来源:互联网 发布:数据查询网站雷阿轮吧 编辑:程序博客网 时间:2024/06/03 23:05

题目链接: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;}


0 0