[枚举,思维]费解的开关


这道题体现了一个重要的思路:当面对一个情况复杂、不知从何下手的问题,而且进行若干操作的结果与它们的顺序无关时,不妨考虑按一定顺序操作,比如一行一行地考虑。
首先,显然每个位置至多操作一次。所以不难得到一个枚举\(2^{25}\)种情况的算法(逃)
但如果我们考虑一行一行地进行处理:
那么当我们固定(不再修改)\(i-1\)行时,有且仅有一种对第\(i\)行的操作,使得第\(i-1\)行全为1:只改变上一行关着的灯下面的灯
也就是说,对第1行进行某种操作后,有且只有一种方案,使前4行全为1。
因此我们只需要枚举第1行的所有可能操作(32种),判断经过上述操作后,第5行是否恰为11111即可

#include <iostream>
using namespace std;

int a[5][5], b[5][5];
int t[32][5];

void init() {
    for (int i = 0; i < 32; i++) {
        for (int j = 0; j < 5; j++) {
            t[i][j] = (i >> (4 - j)) & 1;
        }
    }
}

void input() {
    string s;
    for (int i = 0; i < 5; i++) {
        cin >> s;
        for (int j = 0; j < 5; j++) a[i][j] = s[j] - '0', b[i][j] = a[i][j];
    }
}

void resume() {
    for (int i = 0; i < 5; i++)
        for (int j = 0; j < 5; j++) a[i][j] = b[i][j];
}

bool in(int x) { return x >= 0 && x < 5; }
void change(int x, int y) {
    if (in(x) && in(y)) a[x][y] ^= 1;
    if (in(x + 1) && in(y)) a[x + 1][y] ^= 1;
    if (in(x - 1) && in(y)) a[x - 1][y] ^= 1;
    if (in(x) && in(y + 1)) a[x][y + 1] ^= 1;
    if (in(x) && in(y - 1)) a[x][y - 1] ^= 1;
}


int solve(int t[]) {
    int cnt = 0;
    for (int i = 0; i < 5; i++)
        if (t[i]) change(0, i), cnt++;
    for (int i = 1; i < 5; i++)
        for (int j = 0; j < 5; j++)
            if (!a[i - 1][j]) change(i, j), cnt++;
            
    if (cnt > 6) {
        resume();
        return 7;
    }
    for (int i = 0; i < 5; i++) {
        if (a[4][i] != 1) {
            resume();
            return 7;
        }
    }

    return cnt;
}

int main() {
    init();
    int T;
    cin >> T;
    while (T--) {
        input();
        int ans = 7;
        for (int i = 0; i < 32; i++) {
            ans = min(ans, solve(t[i]));
        }
        ans <= 6 ? cout << ans << endl : cout << -1 << endl;
    }
    return 0;
}
posted @ 2021-11-04 23:32  _vv123  阅读(33)  评论(0编辑  收藏  举报