[remanufacturing] poj-3279 Flipile solution

[remanufacturing] poj-3279 Flipile solution

I'm so weak. I record a violence I can't think of for two days

Title Link: POJ-3279.Fliptile
Students who understand the meaning of the question and just want to see the code suggest jumping here directly: Normal code

subject

meaning of the title

Give you a table composed of 0 and 1. Turn a box. You can change itself and the top, bottom, left and right squares from 0 to 1 and from 1 to 0

Ask you to output an operation table. How can you reverse all 0

Note:

  • The output is the number of steps you operate each box, not the flip result of the original table
  • If there are multiple results, output the one with the smallest dictionary order

Problem solving ideas

  1. The ontology needs violent enumeration. Try every flip case

    However, each grid cannot be tried independently, because there are at most 2 ^ 225 possibilities, which is obviously unreasonable.

    However, you can only use the first line to flip. There are only 2 ^ 15 possibilities at most. It can still be traversed
  2. The second row and each subsequent row can determine whether to flip through the 0 / 1 value of the previous row
  3. The 0 / 1 value of each position can be used to judge its final result through the turnover of four positions [itself, left, right and upper]
    Since the result of this grid is used to judge whether the grid below needs to be flipped, it is not necessary to judge the situation below [detailed below in combination with the code]
  4. By the way, it's 0 / 1 because each grid can be turned once at most, because it's meaningless to turn more

Code block parsing

This module was added because the boss posted a code directly in the comment area below vj without comments at all. I finally understood it bit by bit, so I don't want to waste it.

Main function

#include <iostream>
using namespace std;
typedef int hip;
#include <bitset>

int main() {
        ios::sync_with_stdio(0); cin.tie(0);
        // Enter m rows and n columns of data
        cin >> mLine >> nCloum;
        for (hip i=1;i<=mLine;i++) for (hip j=1;j<=nCloum;j++) cin >> grass[i][j];
        // Defines the minimum number of reversals and the number of reversals
        hip ansFlip = 400;
        hip ansType = -1;
        // Only the first row is enumerated, and then the flipping mode of each row below is calculated according to the flipping result of the first row
        // There are 2^n cases in the first line
        // As an example:
        // 4 4
        // 1 0 0 1
        // 0 1 1 0
        // 0 1 1 0
        // 1 0 0 1
        // The value of iniType is 0 - 15
        // The result of the corresponding first line is
        // 0000,0001,0010,0011,0100,0101,0110,0111
        // 1000,1001,1010,1011,1100,1101,1110,1111
        // These 16 cases
        for (hip iniType = 0; iniType < 1<<nCloum; iniType++) {
                // Use bitset to automatically convert to binary
                bitset<maxn> b = iniType;
                // Record all the turnover times corresponding to this [first line turnover]
                hip flipNum = 0;
                // Mark first line
                for (hip cloumNo = 1; cloumNo <= nCloum; cloumNo++) {
                        f[iniType][1][cloumNo] = b[nCloum - cloumNo];
                        // If you flip, increase the number of records
                        if (b[nCloum - cloumNo]) flipNum += 1;
                }
                // Mark the flipping of the second line and after
                // The marking method is: judge whether the corresponding position of the previous line is 1. If so, flip this grid
                // Traverse the second line and every line after it
                for (hip lineNo = 2; lineNo <= mLine; lineNo++)
                        // Traverse each column
                        for (hip cloumNo = 1; cloumNo <= nCloum; cloumNo++)
                                // after_flip() is to judge whether the four positions of a grid [itself, left, right and upper] need to be flipped
                                // Then return your 0 / 1 value after flipping
                                // What is judged here is the grid in the previous row of this column. If it is 1, mark this grid as [need to be flipped]
                                // And turn the number of times + 1
                                if (after_flip(iniType, lineNo-1, cloumNo))
                                        f[iniType][lineNo][cloumNo] = true, flipNum += 1;
                                else f[iniType][lineNo][cloumNo] = false;
                // After marking the whole map, the upper grid should be 0 except the last line
                // If this flipping scheme is feasible, the last line should also be all 0
                // end_ line_ all_ The zero () function returns whether the last line of this scheme is all 0
                // If all are 0 and the number of flips is the least, the tag is updated
                if (end_line_all_zero(iniType) && ansFlip > flipNum)
                        ansType = iniType, ansFlip = flipNum;
        }
        // If the scheme mark is still - 1, it indicates that there is no feasible scheme, and the output is impossible
        // On the contrary, the corresponding scheme [note format] is output
        if (ansType!=-1) {
                for (hip i=1;i<=mLine;i++) {
                        for (hip j=1;j<=nCloum;j++) {
                                cout << f[ansType][i][j];
                                if (j == nCloum) cout << endl;
                                else cout << ' ';
                        }
                }
        }
        else cout << "IMPOSSIBLE" << endl;
        return 0;
}

after_flip() function - returns the flip result of the previous line

hip mLine, nCloum;
// An array that stores grassland source data
bool grass[maxn][maxn];
// Table to store flipped grass:
// The boss's code is to recalculate the flip table after obtaining the feasible data number
// But for this problem, it will not exceed the limit so
// So here we simply save the flip table of each case
bool f[1<<maxn][maxn][maxn];

//Judge whether the grid here is out of bounds. If not, return true
bool not_out_of_range(hip line, hip cloum) {
        return (line > 0 && line <= mLine && cloum > 0 && cloum <= nCloum);
}

// Coordinates of the next grid change to be judged
hip nextChange[4][2] = {{0,0}, {0,1}, {0,-1}, {-1,0}};

// Returns the result after the grid is affected by the [itself, left, right, top] flip
// The parameter is the data line number and cloum column number of iniType
bool after_flip(hip iniType, hip line, hip cloum) {
        // Initialize tState to its original state
        bool tState = grass[line][cloum];
        // Traverse the other four grids that will affect this grid except the lower one. If you don't cross the boundary and flip it, flip the current grass
        for (hip i = 0; i < 4; i++) {
                hip nextLine = line + nextChange[i][0];
                hip nextCloum = cloum + nextChange[i][1];
                if (not_out_of_range(nextLine, nextCloum) && f[iniType][nextLine][nextCloum])
                        tState = !tState;
        }
        // Returns the flipped state
        return tState;
}

end_line_all_zero() function - Returns whether the last line is all 0

bool end_line_all_zero(hip type) {
        // This function is shown in the question, but you still need to call after_flip() function
        // If it is 1 after flipping, it indicates that it is not all 0 and returns false
        for (hip cloumNo=1;cloumNo<=nCloum;cloumNo++) if (after_flip(type, mLine, cloumNo)) return false;
        // If false is not returned, it means all 0 after turning, then true is returned
        return true;
}

Variable long code

//
// _   _     ___           ____ ___  ____  _____
//| | | |   / _ \ _ __    / ___/ _ \|  _ \| ____|
//| |_| |  | | | | '_ \  | |  | | | | | | |  _|
//|  _  |  | |_| | | | | | |__| |_| | |_| | |___
//|_| |_|___\___/|_| |_|  \____\___/|____/|_____|
//     |_____|
//

#include <iostream>
using namespace std;
typedef int hip;
#include <bitset>
const int maxn = 19;

hip mLine, nCloum;
bool grass[maxn][maxn];
bool f[1<<maxn][maxn][maxn];

bool not_out_of_range(hip line, hip cloum) {
        return (line > 0 && line <= mLine && cloum > 0 && cloum <= nCloum);
}

hip nextChange[4][2] = {{0,0}, {0,1}, {0,-1}, {-1,0}};

bool after_flip(hip iniType, hip line, hip cloum) {
        bool tState = grass[line][cloum];
        for (hip i = 0; i < 4; i++) {
                hip nextLine = line + nextChange[i][0];
                hip nextCloum = cloum + nextChange[i][1];
                if (not_out_of_range(nextLine, nextCloum) && f[iniType][nextLine][nextCloum])
                        tState = !tState;
        }
        return tState;
}

bool end_line_all_zero(hip type) {
        for (hip cloumNo=1;cloumNo<=nCloum;cloumNo++) if (after_flip(type, mLine, cloumNo)) return false;
        return true;
}

int main() {
        ios::sync_with_stdio(0); cin.tie(0);
        cin >> mLine >> nCloum;
        for (hip i=1;i<=mLine;i++) for (hip j=1;j<=nCloum;j++) cin >> grass[i][j];
        hip ansFlip = 400;
        hip ansType = -1;
        for (hip iniType = 0; iniType < 1<<nCloum; iniType++) {
                bitset<maxn> b = iniType;
                hip flipNum = 0;
                for (hip cloumNo = 1; cloumNo <= nCloum; cloumNo++) {
                        f[iniType][1][cloumNo] = b[nCloum - cloumNo];
                        if (b[nCloum - cloumNo]) flipNum += 1;
                }
                for (hip lineNo = 2; lineNo <= mLine; lineNo++)
                        for (hip cloumNo = 1; cloumNo <= nCloum; cloumNo++)
                                if (after_flip(iniType, lineNo-1, cloumNo))
                                        f[iniType][lineNo][cloumNo] = true, flipNum += 1;
                                else f[iniType][lineNo][cloumNo] = false;
                if (end_line_all_zero(iniType) && ansFlip > flipNum)
                        ansType = iniType, ansFlip = flipNum;
        }
        if (ansType!=-1) {
                for (hip i=1;i<=mLine;i++) {
                        for (hip j=1;j<=nCloum;j++) {
                                cout << f[ansType][i][j];
                                if (j == nCloum) cout << endl;
                                else cout << ' ';
                        }
                }
        }
        else cout << "IMPOSSIBLE" << endl;
        return 0;
}

Normal code

#include <iostream>
using namespace std;
typedef int hip;
#include <bitset>
const int maxn = 19;

hip m, n;
bool G[maxn][maxn];
bool f[1<<maxn][maxn][maxn];

bool R(hip l, hip c) {return (l > 0 && l <= m && c > 0 && c <= n);}

hip N[4][2] = {{0,0}, {0,1}, {0,-1}, {-1,0}};

bool F(hip i, hip l, hip c) {
        bool t = G[l][c];
        for (hip _ = 0; _ < 4; _++) {
                hip nl = l + N[_][0], nc = c + N[_][1];
                if (R(nl, nc) && f[i][nl][nc]) t = !t;
        }
        return t;
}

bool E(hip i) {
        for (hip c=1;c<=n;c++) if (F(i, m, c)) return false;
        return true;
}

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

        cin >> m >> n;
        for (hip i=1;i<=m;i++) for (hip j=1;j<=n;j++) cin >> G[i][j];

        hip r = 400;
        hip t = -1;
        for (hip i = 0; i < 1<<n; i++) {
                bitset<maxn> b = i;
                hip fn = 0;
                for (hip c = 1; c <= n; c++) {
                        f[i][1][c] = b[n-c];
                        if (b[n-c]) fn += 1;
                }

                for (hip l = 2; l <= m; l++) for (hip c = 1; c <= n; c++)
                        if (F(i, l-1, c)) f[i][l][c] = true, fn += 1;
                        else f[i][l][c] = false;

                if (E(i) && r > fn) t = i, r = fn;
        }
        if (t!=-1) {
                for (hip i=1;i<=m;i++) for (hip j=1;j<=n;j++)
                        cout << f[t][i][j] << ((j==n)?"\n":" ");
        }
        else cout << "IMPOSSIBLE" << endl;
        return 0;
}

Keywords: C++ Algorithm data structure

Added by wellmoon on Fri, 28 Jan 2022 12:13:26 +0200