【POJ 3279 --- Fliptile】全排列+搜索

【POJ 3279 --- Fliptile】全排列+搜索

题目来源:点击进入【POJ 3279 — Fliptile】

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

解题思路

根据题意我们知道,反转一个点,那么那个点周围的四个点都会被反转。如果一个点反转两次及以上并没有实际意义。因为反转两次后和不反转的情况是一样的。

当前面一行确定时我们要满足将所有格子全部反转为0.那么当前行的反转情况就已经被固定了。
例如:0 1 0 1
那么他们下一行的反转情况肯定是 0 1 0 1 因为我们要将前一行的1给反转掉。

所以,我们只需要遍历第一行的所有情况,然后依次推出后面每一行。判断最后一行是否全为0。如果是则代表可行,反之则不行。

怎么遍历第一行所有情况?
我们可以通过二进制全排列的方式。将所有情况遍历出来。

需要注意的是遍历顺序!因为题上要求了字典序最小。

详情看代码:

AC代码:

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define endl '\n'
const int MAXN = 20;
int m,n,res;
int arr[MAXN][MAXN]; //原数组 系统输入
int ans[MAXN][MAXN]; //存放最终答案的数组
int fz[MAXN][MAXN];  //反转数组,记录反转(i,j)的反转情况
int dir[5][2]={{-1,0},{1,0},{0,-1},{0,1},{0,0}}; // 方向数组,记录当前结点会受哪些结点反转的影响
//获取当前结点(x,y)的颜色(即0或1)
int get_color(int x,int y)
{
    int res=arr[x][y];//获取当前结点在原数组中的颜色情况
    //遍历影响当前结点的所有结点反转情况
    for(int i=0;i<5;i++)
    {
        int dx=x+dir[i][0];
        int dy=y+dir[i][1];
        if(dx<0 || dy<0 || dx>=m || dy>=n) continue;
        res+=fz[dx][dy];
    }
    //返回当前结点颜色
    return res&1;
}

int fun()
{
    int res=0;
    //已知第一行的反转方案,递推后面m-1行的反转情况
    for(int i=1;i<m;i++)
        for(int j=0;j<n;j++)
            if(get_color(i-1,j)) fz[i][j]=1;//若(i-1,j)结点为黑色,需要反转当前结点
    //判断最后一行是否全是0,若不是返回-1
    for(int i=0;i<n;i++)
        if(get_color(m-1,i)) return -1;
    //该方案成立,统计反转总次数
    for(int i=0;i<m;i++)
        for(int j=0;j<n;j++)
            res+=fz[i][j];
    return res;
}

int main()
{
    SIS;
    while(cin >> m >> n)
    {
        res=-1;
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++)
                cin >> arr[i][j];
        //i的范围0-(1<<n - 1)每个i的每个二进制位代表对应位置的反转情况
        for(int i=0;i<(1<<n);i++)
        {
            memset(fz,0,sizeof(fz));
            //给第一行赋值,确定当前方案 
            for(int j=0;j<n;j++) 
                fz[0][n-1-j]=(i>>j)&1;//注意题上要求字典序最小
            int num=fun();
            //如果num满足可更新res的条件,则更新res和ans数组
            if(num>=0 && (res<0 || res>num))
            {
                res=num;
                for(int j=0;j<m;j++)
                    for(int k=0;k<n;k++)
                        ans[j][k]=fz[j][k];
            }
        }
        if(res==-1) cout << "IMPOSSIBLE" << endl;
        else
        {
            for(int i=0;i<m;i++)
                for(int j=0;j<n;j++)
                    cout << ans[i][j] << (j==n-1?'\n':' ');
        }
    }
    return 0;
}
发布了361 篇原创文章 · 获赞 127 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_41879343/article/details/104011838