AcWing 95. 费解的开关 题解

题目

AcWing 95. 费解的开关 题解_第1张图片
AcWing 95. 费解的开关 题解_第2张图片


思路

第一行有五个位置,对应每个位置的操作有两种

  • 改变灯的状态
  • 不改变灯的状态

25=32,即对于第一行的五盏灯的操作一共有32种情况
可以遍历第一行的32种操作情况,然后当第一行的情况确定下来以后,下面从第二行开始, 每一行的变换都是依据上一行灯的亮灭情况:如果上一行是暗的,则把当前这一行同一列的灯改变状态,从而使上一行的灯点亮;如果上一行的灯是亮的,则当前这一行同一列的灯不作改动。
遍历完倒数第二行,最后一行的状态应当保持全亮,如果不是全亮的话,则不符合条件。


代码

#include
#include
using namespace std;
const int N=6;   //为什么是6?因为要保存\0
char g[N][N],backup[N][N];
int dx[5]={-1,1,0,0,0},dy[5]={0,0,-1,1,0};  //偏移量数组,优雅的四周遍历
void turn(int x,int y)
{
    for(int i=0;i<5;i++)
    {
        int a=x+dx[i],b=y+dy[i];
        if(a<0||a>4||b<0||b>4) continue;
        g[a][b]^=1;  //把'0'变‘1’,把‘1’变‘0’
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    
    while(n--)
    {
        int res=1e9;  //答案
        for(int i=0;i<5;i++) cin>>g[i];  //存入灯盘
        memcpy(backup,g,sizeof(g));     //把初始灯盘存个备份,对每种情况都要用初始的灯盘
        for(int op=0;op<32;op++)  //利用位运算遍历这32种情况
        {
            int  step=0;  //记录总步数
            for(int i=0;i<5;i++)  //把每一位的情况抠出来
                if(op>>i&1)     //1代表要改变状态,0代表不改变
                {
                    step++;
                    turn(0,i);
                }
            for(int i=0;i<4;i++)   //当第一行的情况确定,下面每一行的情况也都确定了
                for(int j=0;j<5;j++)
                    if(g[i][j]=='0')
                    {
                        step++;
                        turn(i+1,j);
                    }
            bool dark=false;
            for(int i=0;i<5;i++)      //判断最后一行的情况是不是全量
                if(g[4][i]=='0')
                {
                    dark=true;
                    break;
                }
            if(!dark) res=min(res,step);
            memcpy(g,backup,sizeof(backup));  //还原备份,重新去判断下一种情况
        }
        if(res>6)
            printf("-1\n");
        else
            printf("%d\n",res);
    }
    return 0;
}

你可能感兴趣的:(#,蓝桥杯,code,刷题,总结&记录,递推,位运算)