poj1753枚举

从今天开始把做过的题记录下来。

Flip Game

从翻纸牌的规则可以看出:翻转第i+1行第j列的纸牌,会改变第i 行第j列的纸牌状态,但不影响第i行的其它纸牌。所以,通过翻转下一行的某些纸牌,能达到使上一行纸牌全黑(或全白)的目的。翻完最后一行时,检验最后一行是否全黑(或全白),即可决定此次翻转是否合格且能作为备选方案。

枚举第0行的所有操作,每张纸牌都可能“翻转”或“不翻转”。

process 函数找出将纸牌做成全白(或全黑)的所有操作可能,并返回最小操作数。k[0]到k[3]表示:第0行第0到3列的操作(“翻”或“不翻”)。对某一第0行可能的状态,后面几行的操作就遵循使上一行变成全白(或全黑)的规则,直到最后一行。如果最后一行的状态满足要求,则把这次的翻转次数作为一个候选者。枚举完所有第0行的可能状态,就得到最小翻转次数。

flip 函数进行了翻转(i,j)位置纸牌的操作。布尔值valid 表示最后一行是否满足要求。

#include <cstdio>
#include <iostream>
#include <cmath>
#include <climits>
#include <cstring>
using namespace std;

const int dim = 4;
void flip(int aux[][dim], int i, int j) {
    aux[i][j] = !aux[i][j];
    if (i > 0) aux[i-1][j] = !aux[i-1][j];
    if (i < dim-1) aux[i+1][j] = !aux[i+1][j];
    if (j > 0) aux[i][j-1] = !aux[i][j-1];
    if (j < dim-1) aux[i][j+1] = !aux[i][j+1];
}

int process(char board[][dim+1], int aux[][dim], bool getWhite) {
    int k[4];
    int cnt = 0;
    int minCnt = INT_MAX;

    for (k[0] = 0; k[0] <= 1; ++k[0])
        for (k[1] = 0; k[1] <= 1; ++k[1])
            for (k[2] = 0; k[2] <= 1; ++k[2])
                for (k[3] = 0; k[3] <= 1; ++k[3]) {

                    cnt = 0;
                    for (int i = 0; i < dim; ++i)
                        for (int j = 0; j < dim; ++j)
                            aux[i][j] = (board[i][j] == 'w');
                    for (int j=0; j<dim; ++j) {
                        if (k[j]) {
                            flip(aux,0,j);
                            ++cnt;
                        }
                    }
                    for (int i=1; i<dim; ++i) {
                        for (int j=0; j<dim; ++j) {
                            if (getWhite && !aux[i-1][j]) {
                                flip(aux,i,j);
                                ++cnt;
                            }
                            if (!getWhite && aux[i-1][j]) {
                                flip(aux,i,j);
                                ++cnt;
                            }
                        }
                    }
                    bool valid = true;
                    for (int j=0; j<dim; ++j) {
                        if (getWhite && !aux[dim-1][j]) valid = false;
                        if (!getWhite && aux[dim-1][j]) valid = false;
                    }
                    if (valid) minCnt = min(minCnt, cnt);
    }
    return minCnt;
}
int main() {
    char board[dim][dim+1];
    int aux[dim][dim];
    for (int i = 0; i < dim; ++i) {
        cin.getline(board[i], dim+1);
    }
    bool white = true;
    int cnt1 = process(board, aux, white);
    int cnt2 = process(board, aux, !white);
    if (min(cnt1,cnt2) == INT_MAX) printf("Impossible\n");
    else printf("%d\n", min(cnt1,cnt2));
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值