费解的开关(BFS+哈希表+二进制枚举)

news2024/9/24 13:25:42

费解的开关(BFS+哈希表+二进制枚举)

  • 一、题目
  • 二、思路分析
    • 1、算法标签
    • 2、思路梳理
      • 方法1:BFS+哈希表
      • 方法2:二进制枚举+DFS

一、题目

在这里插入图片描述

二、思路分析

1、算法标签

这道题考察的是BFS+哈希表,DFS+二进制枚举

2、思路梳理

方法1:BFS+哈希表

这道题的思路和作者之前讲解的八数码的问题是很接近的思路。

如果大家不了解那道题的话,作者建议大家去看一看那道题,二者的思路是一样的。传送门:

八数码(BFS+哈希)

在讲解方法一的思路之前,我们先来做一下铺垫:
这道题的题面给出了一个二维矩阵,又问的是最小操作次数问题,那么我们很容易联想到利用搜索处理。

但是搜索的话,我们并不是在题目给出的一个二维矩阵里进行不断地变化。

我们是把一个二维矩阵看作一个点而点与点之间的边其实就是二维矩阵发生变化时的操作。

简而言之,我们不是将一个字符看作一个点,而是将一个状态看作一个点。

而我们如何将一个二维矩阵看成一个点呢?我们发现这道题中的矩阵是由01组成的,因此,我们可以将矩阵中的25个0或1压缩成一个二进制数字,然后将这个二进制数字转化为十进制存储起来。

然后我们的终点就是二维数组中25个数字全为1的时候,此时这个数就是 2 5 − 1 2^5-1 251

我们知道这个时间复杂度是很高的,那么为了避免不断地搜索,我们可以从反面思考,我们将终点状态,即25个1的状态,看作起点,然后从这个点出发,去枚举出6次操作以内所能够形成的所有状态。然后我们用状态去索引操作次数,故为了提高索引的效率,我们采用哈希表。后续只需要根据输入查表即可。

但是,这样的时间复杂度相当高,所以我们要及时终止,由于BFS具有最短路的性质,因此当我们从队列中取出了一个操作次数为6的状态的时候,我们就可以终止了,因为后续的状态所需的操作次数都是大于等于6的。

代码如下:

#include<iostream>
#include<unordered_map>
#include<queue>
using namespace std;
int a[30];
unordered_map<int,int>dis;
int n;
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
void bfs()
{
  queue<int>q;
  int end=(1<<25)-1;
  dis[end]=0;
  for(int i=0;i<25;i++)
  {
    int j=end-a[i];
    for(int k=0;k<4;k++)
    {
        int nx=i/5+dx[k],ny=i%5+dy[k];
        if(nx>=0&&nx<5&&ny>=0&&ny<5)
        {
            j-=a[nx*5+ny];
        }
    }
    q.push(j);
    dis[j]=1;
  }
  while(!q.empty())
  {
    int t=q.front();
    q.pop();
    int distance=dis[t];
    if(distance==6)return;
    string s1;
    for(int i=0;i<25;i++)
    {
      if(t>>i&1)s1+='1';
      else s1+='0';
    }
    
    for(int i=0;i<25;i++)
    {
        int tmp=t;
        string ts=s1;
        int x=i/5,y=i%5;
        for(int j=0;j<4;j++)
        {
            int nx=x+dx[j],ny=y+dy[j];
            if(nx>=0&&nx<5&&ny>=0&&ny<5)
            {
                s1[nx*5+ny]='1'-s1[nx*5+ny]+'0';
                if(s1[nx*5+ny]=='1')t+=a[nx*5+ny];
                else t-=a[nx*5+ny];
            }
        }
        s1[i]='1'-s1[i]+'0';
        if(s1[i]=='1')t+=a[i];
        else t-=a[i];
        int d=distance+1;
        if(d<=6&&(!dis.count(t)))
        {
            dis[t]=d;
            q.push(t);
        }
        t=tmp;
        s1=ts;
    }
  }  
}
int main()
{
  for(int i=0;i<25;i++)
  {
    a[i]=1<<i;
  }
  bfs();
  cin>>n;
  string s1;
  while(n--)
  {
    int res=0;
    for(int i=0;i<25;i++)
    {
      char c;
      cin>>c;
      if(c=='1')res+=a[i];
    }
    if(dis.count(res))
      printf("%d\n",dis[res]);
    else
      printf("-1\n");
  }
}

方法2:二进制枚举+DFS

我们发现方法一的特点就是简单粗暴,但是代码量很大,并且效率很低。

我们现在来研究一下这道题中的某些性质:

1、灯是否全亮只取决于你按了哪些灯,但是这些灯之间被按的顺序是没有用的。为什么?对于每个灯而言,他的变化也就是从不亮到亮,或者亮到不亮。这个变化只取决于这个灯原来的状态,和顺序无关。

2、最少的操作次数中,某个被按的灯一定是只被按了一次。因为如果按两次,相当于这个灯没被按,如果按奇数次的话,那这个效果和只按一次是一样的。

既然最优的方案只和按哪些灯有关,和操作之间的顺序无关的话,我们就人为的规定一下操作的顺序:

从第一层逐层向下。

我们现在看这种方式:

在这里插入图片描述
如果第一行,我们固定不变,那么能够让第一行中灭掉的灯变亮的方式只能是去按第二层对应的灯。我们可以靠第二层产生的连锁反应让第一行对应的灯变亮。

但同样的情况,我们第二行的某些亮着的灯可能也会被灭掉,因此,我们可以通过操作第三层的灯,来让第二层灭掉的灯变亮。

但是很明显,我们的最后一行是无法通过以上的方式点亮。若能够点亮的话,只能是通过倒数第二层的连锁反应让最后一层自动点亮。这样的话就是可行的操作。

但是,我们的第一行怎么按是不确定的。

而又因为按哪些灯和我们的方案有关,那么我们就需要去枚举所有方案,看看是不是存在可行的方案。而由于一个方案后续的操作完全取决于第一行,**因此我们只需要去枚举第一行的所有操作情况即可。**后续行的操作可以从第一行逐级推导出来。

而第一行的操作可能共有 2 5 2^5 25次方种可能。所以我们可以枚举从 0 0 0 2 5 − 1 2^5-1 251,然后看这些数字的二进制位,如果二进制位是1,意思就是操作,二进制位是0,意思就是不操作。

#include<iostream>
#include<cstring>
using namespace std;
const int N=6;
char g[N][N],backup[N][N];
int dx[5]={-1,0,1,0,0},dy[5]={0,1,0,-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<5&&b>=0&&b<5)
            g[a][b]^=1;
    }
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        for(int i=0;i<5;i++)cin>>g[i];
        int res=10;
        for(int op=0;op<32;op++)
        {
            memcpy(backup,g,sizeof g);
            int step=0;
            for(int i=0;i<5;i++)
            {
                if(op>>i&1)
                {
                    step++;
                    turn(0,i);
                }
            }
            for(int i=0;i<4;i++)
            {
                for(int j=0;j<5;j++)
                {
                    if(g[i][j]=='0')
                    {
                        turn(i+1,j);
                        step++;
                    }
                }
            }
            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 g);
        }
        if(res>6)res=-1;
        cout<<res<<endl;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/131884.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Cohen–Sutherland 算法介绍(简单易懂)

目录 一、算法介绍 二、算法描述 三、算法总结 一、算法介绍 Cohen–Sutherland 算法用于直线段裁剪&#xff0c;通过判断直线与窗口之间的关系&#xff0c;来决定直线段部分的保留与舍弃。 二、算法描述 ① 首先&#xff0c;我们把屏幕分割成 9 个区域块&#xff0c;最中间区…

音乐相册如何制作?一步一步教会你

很多小伙伴会在旅行时&#xff0c;拍摄各种好看的照片&#xff0c;一趟旅途下来能留下好多照片呢&#xff0c;有些人会习惯将这些照片归类到一个相册里。其实我们也可以使用一些免费的软件将这些照片制作成有纪念意义的音乐相册&#xff0c;那大家知道免费制作音乐相册怎么做吗…

npm install 报警告npm WARN

npm install 报警告npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents1.2.0 (node_modules\fsevents npm notice created a lockfile as package-lock.json. You should commit this file. npm WARN fsevents1.2.0 had bundled packages that do not match the requi…

Crack:Inobitec DICOM Viewer Pro 2.9 多语言版本

Inobitec DICOM Viewer Pro 的使命是扩大医生可见和可能的范围。通过为医学提供高质量的创新 IT 解决方案&#xff0c;Ω578867473为改善全世界人民的健康做出了贡献。感受到自己工作的价值&#xff0c;意识到 21 世纪医学面临的挑战的重要性&#xff0c;以及解决这些挑战的乐趣…

WordPress使用二级域名存储图片等静态资源达到网站加速的详细配置

最近发现源站压力较大&#xff08;水管太小&#xff09;于是想着把WordPress博客的图片等静态资源分离到二级域名中&#xff0c;二级域名再使用一次云盾免费加速CDN&#xff0c;达到动静分离的效果&#xff0c;在这个过程中遇到一些坑&#xff0c;特此记录一下&#xff0c;方便…

NumpyPandas 数据处理与挖掘

笔记来源B站&#xff1a;https://www.bilibili.com/video/BV1xt411v7z9?p21 python学习笔记1 Numpy1.1 Numpy优势1.1.1 Numpy介绍1.1.2 ndarray介绍1.1.3 ndarray与Python原生list效率对比1.1.4 ndarray优势1.2 认识N维数组-ndarray属性1.2.1 ndarray的属性1.2.2 ndarray的形状…

11.1、基于Django4的可重用、用户注册和登录系统搭建

文章目录系统的功能思路分析搭建项目环境创建项目&#xff08;虚拟环境&#xff09;创建子应用修改语言、时区创建数据库表启动项目git提交项目代码到本地仓库git initi 初始化&#xff0c;创建本地git仓库pycharm安装 .ignore插件&#xff0c;来设置git的忽略文件提交代码修改…

SpringBoot+VUE前后端分离项目学习笔记 - 【09 SpringBoot集成MyBatis-Plus和SwaggerUI】

集成mybatis-plus依赖 官网 : https://baomidou.com/ pom.xml <!-- mybatis-plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></depe…

01月份图形化一级打卡试题

活动时间 从2023年 1月1日至1月21日&#xff0c;每天一道编程题。 本次打卡的规则如下&#xff1a; &#xff08;1&#xff09;小朋友每天利用10~15分钟做一道编程题&#xff0c;遇到问题就来群内讨论&#xff0c;我来给大家答疑。 &#xff08;2&#xff09;小朋友做完题目后&…

认证的未来:2023 年值得关注的四大趋势

在经济不确定性和地缘政治紧张的一年中&#xff0c;数字领域充满网络威胁也就不足为奇了。从广泛的假冒诈骗到日益增多的短信网络钓鱼&#xff0c;网络攻击的频率和严重程度在 2022 年有所增加&#xff0c;这突显了所有行业的组织身份验证漏洞。 因此&#xff0c;当我们翻开新…

amis组件学习的配置介绍(二)

table view 表格视图 这个看文档也很好理解&#xff0c;但是还是需要介绍一下。 trs&#xff1a; <Array>设置表格行属性。tds: <Array>设置单元格属性。 {"type": "table-view",// 设置表格行"trs": [{"background": &…

常见排序算法(上)

篮球哥温馨提示&#xff1a;编程的同时不要忘记锻炼哦&#xff01;稳定的排序算法&#xff0c;可以设计成不稳定的. 目录 1、 认识排序 2、常见排序的分类 3、直接插入排序 4、希尔排序(缩小增量排序) 5、选择排序 6、堆排序 1、 认识排序 在学校中&#xff0c;如果我们…

QML学习笔记【03】:动画

动画是在指定的时间内&#xff0c;一系列属性的持续变化 1 动画元素&#xff08;Animation Elements&#xff09; 有几种类型的动画&#xff0c;每一种都在特定情况下都有最佳的效果&#xff0c;下面列出了一些常用的动画&#xff1a; PropertyAnimation&#xff08;属性动画…

人工智能学习07--pytorch01

一、pytorch简介 1、与TensorFlow区别 2、常用网络层 二、pytorch需要&#xff1a; 1、anaconda 2、CUDA 只能在NVIDIA上运行 ↓我发现电脑果然没有这个显卡 https://zhidao.baidu.com/question/2084255692200398828.html 3、pycharm 新项目要配置python的编译器&#xff…

Leetcode 36. 有效的数独

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 &#xff0c;验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&#xff08;请参考示例图&#xff09;注意…

FastDfs分布式文件存储系统

FastDfs分布式文件存储系统 FastDfs 是一个开源的高性能分布式文件系统&#xff08;DFS&#xff09;。 它的主要功能包括&#xff1a;文件存储&#xff0c;文件同步和文件访问&#xff0c;以及高容量和负载平衡。主要解决了海量数据存储问题&#xff0c;特别适合以中小文件&am…

基于Springboot+Mybatis+mysql+vue+html校园招聘管理系统

基于SpringbootMybatismysqlvuehtml校园招聘管理系统二、系统介绍三、功能展示1.首页2.个人中心(学生端)3.简历信息管理&#xff08;学生端&#xff09;4.应聘信息(学生端)5.企业信息&#xff08;企业&#xff09;6.招聘信息管理&#xff08;企业&#xff09;7.应聘信息管理&am…

谷粒学院——Day15【微信支付】

❤ 作者主页&#xff1a;Java技术一点通的博客 ❀ 个人介绍&#xff1a;大家好&#xff0c;我是Java技术一点通&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 记得关注、点赞、收藏、评论⭐️⭐️⭐️ &#x1f4e3; 认真学习&#xff0c;共同进步&#xff01;&am…

【观察】美达电器:以数字化重塑质量管理体系,构筑车企新“护城河”

在汽车行业&#xff0c;越来越多的企业走上数字化转型道路&#xff0c;运用数字化手段&#xff0c;从产品研发、生产制造、供应链管理等方面优化内部协同&#xff0c;从而降低管理成本&#xff0c;提升市场竞争力。美达电器(重庆)有限公司&#xff08;以下简称美达电器&#xf…

day17-缓冲流转换流序列化流打印流Properties

day17_JAVAOOP 课程目标 1. 【理解】什么是缓冲流 2. 【掌握】缓冲流的使用 3. 【理解】转换流 4. 【理解】序列化流 5. 【理解】打印流 6. 【掌握】Properties集合的使用缓冲流 ​ 前期我们学习了基本的一些流&#xff0c;作为IO流的入门&#xff0c;今天我们要见识一些更强…