kuangbin专题一 简单搜索 翻转(POJ-3279)

发布时间 2023-04-14 20:46:36作者: Amαdeus

Fliptile

Time Limit: 2000MS Memory Limit: 65536K

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 矩阵,矩阵中只有0和1两种值,现在我们需要将矩阵中所有的元素变为0。我们可以进行一种翻转的操作,若选定(i,j)翻转,同时须将其上、下、左、右四个方向进行翻转(翻转即0变成1,1变成0)。问步数最少且字典序最小的方案。输出一个矩阵,1代表(i,j)被翻转,0代表不被翻转。



解题思路

这道题很容易让人联想到一道题 ———— 费解的开关,其实几乎完全一样的递推做法,只不过需要输出具体的方案,只需要另开一个数组存储具体方案即可。题目中要求字典序最小,因为是从上往下递推的,所以只需要记录步数最短的第一个方案就可以了。

/*   一切都是命运石之门的选择  El Psy Kongroo  */
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<cmath>
#include<functional>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<int, pii> piii;
typedef pair<double, double> pdd;
typedef pair<string, pii> psi;
typedef __int128 int128;
#define x first
#define y second
const int inf = 0x3f3f3f3f, mod = 1e9 + 7;

#include<iostream>
#include<cstring>
using namespace std;

const int N = 16;
int g[N][N], backup[N][N];   //当前图状态  图状态备份
int ans[N][N], tmp[N][N];    //记录答案  当前翻转方案
int n, m;
int minstep = 1e9;
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};

//翻转
void turn(int x, int y){
    g[x][y] ^= 1;
    for(int k = 0; k < 4; k ++ ){
        int nx = x + dx[k], ny = y + dy[k];
        if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
        g[nx][ny] ^= 1;
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    cin >> n >> m;
    for(int i = 0; i < n; i ++ )
        for(int j = 0; j < m; j ++ ) 
            cin >> g[i][j];

    //状态压缩  枚举状态  二进制为1表示第一行次列进行翻转
    for(int sta = 0; sta < (1 << m); sta ++ ){
        memset(tmp, 0, sizeof(tmp));
        memcpy(backup, g, sizeof(g));

        int step = 0;    //得到第一行的状态
        for(int k = 0; k < m; k ++ ){
            if(sta >> k & 1){
                tmp[0][k] = 1;
                turn(0, k);
                step ++ ;
            }
        }

        for(int i = 0; i < n - 1; i ++ ){   //查看0-n-2行的状态,第(i + 1, j)处若为1需翻转其下面的位置
            for(int j = 0; j < m; j ++ ){
                if(g[i][j] == 1){
                    tmp[i + 1][j] = 1;
                    turn(i + 1, j);
                    step ++ ;
                }
            }
        }

        bool all_dark = true;          //查看最后一行是否全为0
        for(int i = 0; i < m; i ++ )
            if(g[n - 1][i]){
                all_dark = false;
                break;
            }

        if(all_dark && step < minstep){ //更新答案
            memcpy(ans, tmp, sizeof(tmp));
            minstep = step;
        }

        memcpy(g, backup, sizeof(backup));
    }

    if(minstep == 1e9){
        cout << "IMPOSSIBLE" << endl;
        return 0;
    }
    
    for(int i = 0; i < n; i ++ ){
        for(int j = 0; j < m; j ++ )
            cout << ans[i][j] << ' ';
        cout << endl;
    }

    return 0;
}