题解:POJ 3279 Fliptile (BFS)

时间:2021-10-07 00:17:46

D - Fliptile

Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%I64d &%I64u

Description

Farmer John knows that an intellectually satisfied cow is
a happy cow who will give more milk. He has arranged a brainy activity
for cows in which they manipulate an M × N grid (1 ≤ M ≤ 15; 1 ≤ N ≤
15) of square tiles, each of which is colored black on one side and
white on the other side.

As one would guess, when a single white tile is flipped, it changes to
black; when a single black tile is flipped, it changes to white. The
cows are rewarded when they flip the tiles so that each tile has the
white side face up. However, the cows have rather large hooves and
when they try to flip a certain tile, they also flip all the adjacent
tiles (tiles that share a full edge with the flipped tile). Since the
flips are tiring, the cows want to minimize the number of flips they
have to make.

Help the cows determine the minimum number of flips required, and the
locations to flip to achieve that minimum. If there are multiple ways
to achieve the task with the minimum amount of flips, return the one
with the least lexicographical ordering in the output when considered
as a string. If the task is impossible, print one line with the word
“IMPOSSIBLE”.

Input

Line 1: Two space-separated integers: M and N Lines 2.. M+1:
Line i+1 describes the colors (left to right) of row i of the grid
with N space-separated integers which are 1 for black and 0 for white

Output

Lines 1.. M: Each line contains N space-separated integers, each
specifying how many times to flip that particular location.

Sample Input

4 4
1 0 0 1
0 1 1 0
0 1 1 0
1 0 0 1

Sample Output

0 0 0 0
1 0 0 1
1 0 0 1
0 0 0 0

大致题意

有一个n*m的范围摆满了瓦片。 瓦片有黑白两面, 1代表黑色, 0 代表白色。 每次点击一个瓦片的时候, 它和它上下左右的5个瓦片都会同时反转过来。 问点击次数最小的点集方法(存在点集次数相同的不同方法的时候, 输出字典序最小的), 如果不存在输出IMPOSSIBLE

分析

这道题和 BestCoder Round #69 (div.1 )Baby Nero and Binary image有点相似之处

我们来枚举第一层(因为在点击的过程中, 点击第n层会影响第n - 1, n, n + 1层, 而第一层的上一层不存在, 所以我们特殊考虑);

现在来讲解对于第1层的枚举:

int MAX = 1 << m;
for (k = 0; k < MAX; k++)  //枚举第一行的状态
{
    for (j = 0; j < m; j++)
    {
        if (k & (1 << j))
        {
            …………
        }
    }
    …………
}

现在我们注意到点击点(i,j)的时候(i - 1)层的点只会影响到(i - 1, j), 所以我们进行如下的处理: 当(i - 1, j)的值为1的时候, 我们点击点(i, j);

为此我们进行如下的BFS

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
#define INF 0xfffffff
#define ll long long
#define N 20

int n, m;
int res;
int mpt[N][N];  //原始状态
int ans[N][N];  //保存答案
int tmp[N][N];  //翻转模拟数组
int vis[N][N];  //记录是否翻转

void flip(int i, int j)
{
    tmp[i][j] ^= 1;
    if (i - 1 >= 0) 
        tmp[i - 1][j] ^= 1;
    if (i + 1 < n) 
        tmp[i + 1][j] ^= 1;
    if (j - 1 >= 0) 
        tmp[i][j - 1] ^= 1;
    if (j + 1 < m) 
        tmp[i][j + 1] ^= 1;
}

int solve()
{
    for (int i = 1; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            if (tmp[i - 1][j])
            {
                flip(i, j);
                vis[i][j] = 1;
            }
        }
    }
    int time = 0;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            time += vis[i][j];
            if (tmp[i][j]) 
                return INF;
        }
    }
    return time;
}
int main()
{
    int i, j, k;
    while (scanf_s("%d%d", &n, &m) != EOF)
    {
        res = INF;
        for (i = 0; i < n; i++)
        {
            for (j = 0; j < m; j++)
            {
                scanf_s("%d", &mpt[i][j]);
            }
        }
        int MAX = 1 << m;
        for (k = 0; k < MAX; k++)  //枚举第一行的状态
        {
            memset(vis, 0, sizeof(vis));
            memcpy(tmp, mpt, sizeof(mpt));
            for (j = 0; j < m; j++)
            {
                if (k & (1 << j))
                {
                    flip(0, j);
                    vis[0][j] = 1;
                }
            }
            int time = solve();
            if (time < res)
            {
                res = time;
                memcpy(ans, vis, sizeof(vis));
            }
        }
        if (res == INF) cout << "IMPOSSIBLE\n";
        else
        {
            for (i = 0; i < n; i++)
            {
                for (j = 0; j < m; j++)
                {
                    if (j) 
                        cout << ' ';
                    cout << ans[i][j];
                }
                cout << endl;
            }
        }
    }
    return 0;
}