《算法竞赛进阶指南》-AcWing-95. 费解的开关-题解

Posted Tisfy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《算法竞赛进阶指南》-AcWing-95. 费解的开关-题解相关的知识,希望对你有一定的参考价值。

费解的开关

传送门

问题描述

5 × 5 5\\times5 5×5 01 01 01地图, 0 0 0代表这个灯是关着的, 1 1 1代表是开着的。

每次点击一盏灯,它及它的上下左右共 5 5 5盏灯的开关状态都会发生置换。

问你能不能在 6 6 6步之内把所有的灯点亮。

样例输入

3
00111
01011
10001
11010
11100

11101
11101
11110
11111
11111

01111
11111
11111
11111
11111

样例输出

3
2
-1

解题思路

不如先枚举第一行的每个灯的点与不点( 2 5 = 32 2^5=32 25=32种情况),之后第一行就不再动了,第一行没亮的灯由第二行对应的那盏灯点亮。

最后看最后一行是否都是亮着的。

剪枝:中途一旦遇到步数已经大于6就退出。

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
#define size 5
bool mp[size][size]; // 这个用来保存输入
bool test[size][size]; // 这个是用来尝试的数组,每次copy自mp,之后随便改
void debug(bool mp[size][size]) // debug用,打印当前数组
{
    for(int i=0;i<size;i++)
    {
        for(int j=0;j<size;j++)
            cout<<mp[i][j];
        puts("");
    }
}
void scan() // 输入用
{
    for (int i = 0; i < size; i++)
    {
        string s;
        cin>>s;
        for(int j=0;j<size;j++)
            mp[i][j]=s[j]=='1';
    }
}
int dir[5][2]={{-1,0},{1,0},{0,-1},{0,1},{0,0}}; // 这个点开始,上下左右中,共影响5个点
void click(int x, int y)
{
    // puts("Before click:");
    // debug(test);
    for(int i=0;i<5;i++) // 遍历这5个点
    {
        int tx=x+dir[i][0]; // toX:要到的x是当前的x加上步长
        int ty=y+dir[i][1];
        if(tx>=0&&tx<size&&ty>=0&&ty<size) // 如果没有出界
            test[tx][ty]^=1; // 开变成关,关变成开
            // test[tx][ty]=~test[tx][ty]; // 不可以!
    }
    // printf("After clicked (%d, %d):\\n",x,y);
    // debug(test);
}
void copy() // 把mp赋值给test
{
    for(int i=0;i<size;i++)
        for(int j=0;j<size;j++)
            test[i][j]=mp[i][j];
}
int execute(int step) // 执行函数
{
    // debug(test);//*******
    for(int i=1;i<size;i++) // 第2~5行
    {
        for(int j=0;j<size;j++) // 第1~5个
        {
            if(!test[i-1][j]) // 如果是关着的
            {
                click(i,j); // 点击
                step++; // 步数+1
                if(step>6)return step; // 剪枝
            }
        }
    }
    // debug(test);//*******
    for(int j=0;j<size;j++) // 遍历最后一行的每一盏灯
        if(!test[size-1][j]) // 如果是关着的
            return 7; // 不可以
    return step;
}
int main()
{
    int N;
    cin >> N;
    while (N--)
    {
        scan(); // 读入
        int m_step=7; // 最小步数(7已经代表不行了)
        for(int i=0;i<1<<size;i++) // 枚举第一行的所有状态
        {
            copy(); // 复制给test
            int step=0;
            for(int j=0;j<size;j++) // 遍历这个状态数的每一位
                if(i>>j&1) // 如果这一位是1
                    click(0,j),step++; // 点击这个点(其实j反了也无所谓,因为枚举了每一种状态)
            step=execute(step); // 执行
            m_step=min(m_step,step); // 取最优
        }
        cout<<(m_step<=6?m_step:-1)<<endl; // 输出
    }
    return 0;
}

原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/119274660

以上是关于《算法竞赛进阶指南》-AcWing-95. 费解的开关-题解的主要内容,如果未能解决你的问题,请参考以下文章

算法竞赛进阶指南做题记录

《算法竞赛进阶指南》-AcWing-96. 奇怪的汉诺塔-题解

《算法竞赛进阶指南》-AcWing-96. 奇怪的汉诺塔-题解

算法刷题AcWing 95. 费解的开关——递推

AcWing 95 费解的开关

AcWing - 95 - 费解的开关 = bfs