费解的开关

wuchangjian2021-10-25 01:00:03编程学习

在这里插入图片描述

思路一:枚举所有情况,225种方案,时间复杂度高,超时。

所以我们需要挖掘一下其中有没有什么规律,由于对每一个开关操作,它的上下左右都会发生改变。与之前飞行员兄弟该题同理。
1.对同一个开关重复操作没有意义,即在每一个方案中,一个开关有且仅可能执行一次。
2.各个开关的执行顺序不影响最后的结果。
3.当有一行全1后,我们要对它相邻一行i执行状态更换,只能通过(i+1)操作,而不影响全1那行。这里我们从第一行开始看,当我们确定了第一行的操作后,后续每一行的操作方案都是固定的,即当第一行只剩下最后一个0时,要将该位的0变为1,我们只能通过第二行对应的该位操作。
在这里插入图片描述
以上图为例,要将第一行变为全1,即将(1,3)变为1,在第一行任何位置操作都不可能满足条件。有且只有在第二列的同一行(2,3)执行操作。而第四行要使其变为全1,我们则需要在第五行操作。
所以我们还可以得出,如果当前四行全部满足条件时,即全1,第五行仍然有0存在,那么接下来不管如何操作,都不可能实现全1.

由上可知我们需要做的第一步是确定第一行的操作方案,第一行确定后,后面的操作也就固定了。对于第一行我们可以将其以一个5位的二进制数表示,那么一共有25中可能,即32种操作方案。
比如在二进制下表示为10101,表示选择按第一行编号为0,2,4的开关执行操作。那么在第一行将执行3次开关操作。第一行固定后,看第一行是否还有0,有就对第二行操作,没有则查看第二行是否有0存在,然后对第三行操作,依次递推到第四行。
我们可以枚举每一种操作方案,比较每一种方案中能实现目的以及操作次数即可得到最少的执行次数。

代码:

#include<iostream>
#include<string.h>
using namespace std;
int n;
char state[5][5];
char backup[5][5];//备份
void turn(int x,int y)
{
    state[x][y]^=1;
    if(x>0 && x<5) state[x-1][y]^=1;
    if(x>=0 && x<4) state[x+1][y]^=1;
    if(y>0 && y<5) state[x][y-1]^=1;
    if(y>=0 && y<4) state[x][y+1]^=1;
}
int open()
{
    int ans=1000000;//存储最少方案的次数
    for(int i=0;i<1<<5;i++)//枚举第一行所有可能的解决方案
    {
        memcpy(backup,state,sizeof(backup));//备份初始状态用于回溯
        int count=0;//记录每一种操作方案需要的次数
        for(int k=0;k<5;k++)//对第一行的操作计数
            if(i>>k&1)//检查对哪些开关操作
            {
                count++;
                turn(0,k);
            }
        for(int i=0;i<4;i++)//第一行固定后,只能操作后四行
        					//在可行方案中,第五行和第四行应该同时为全1
            for(int j=0;j<5;j++)
                if(state[i][j]=='0')//如果该位是0,对下一行同列的操作使0->1
                {
                    turn(i+1,j);
                    count++;
                }
        bool flag=true;//标识方案是否成功
        for(int j=0;j<5;j++)
            if(state[4][j]=='0')//对每一行操作后如果最后一行还有0,说明方案失败
            {
                flag=false;
                break;
            }
        if(flag) ans=min(ans,count);//方案可行,记录到目前为止的最少次数
        memcpy(state,backup,sizeof(state));//把state回溯到初始状态
    }
    if(ans>6) ans=-1;
    return ans;
}


int main()
{
    cin>>n;
    while(n--)
    {
        for(int j=0;j<5;j++)
            cin>>state[j];
        //cout<<endl;
        cout<<open()<<endl;
    }
    return 0;
}

相关文章

linux下的extcon驱动小析

      量产的项目遇到一个问题,10%的充电线不充电。将这些不良的充电...

android蓝牙

第一次写博客,想到的话题就是现在正在做的一个方向,手机软件-...

【java基础】线程的生命周期、创建的两种方式及使用、线程的同步

目录  一、概念 1、程序、进程、线程 二、线程的创建和使用 1、通过继承Thr...

《数据清洗》8.3.3 加载时间数据至时间维度表

需求:数据库中生成86400条数据 每条数据对应一天的1秒 起始&#x...

单例模式、使用getInstance()方法的原因及作用

先举例说明: 下面是一个例子,为什么要把这个类实例化&#x...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。