费解的开关(BFS+哈希表+二进制枚举)
创始人
2024-05-03 22:44:20
0

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

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

一、题目

在这里插入图片描述

二、思路分析

1、算法标签

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

2、思路梳理

方法1:BFS+哈希表

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

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

八数码(BFS+哈希)

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

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

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

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

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

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

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

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

代码如下:

#include
#include
#include
using namespace std;
int a[30];
unordered_mapdis;
int n;
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
void bfs()
{queueq;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<>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]);elseprintf("-1\n");}
}

方法2:二进制枚举+DFS

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

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

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

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

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

从第一层逐层向下。

我们现在看这种方式:

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

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

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

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

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

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

#include
#include
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<

相关内容

热门资讯

微信安卓系统转苹果系统,轻松实... 你有没有想过,从微信安卓系统转到苹果系统,这中间的转换过程,就像是一场说走就走的旅行,充满了未知和惊...
如何刷安卓8.0系统,安卓8.... 你有没有想过,让你的安卓手机升级到最新的8.0系统,让它焕发出全新的活力呢?别急,今天我就来给你详细...
安卓系统里查看路由,安卓系统下... 你是不是也和我一样,对家里的无线网络充满了好奇?想知道安卓手机里怎么查看路由器信息?那就跟着我一起探...
手机出现安卓系统信号,手机信号... 你有没有发现,最近你的安卓手机信号好像变得特别不稳定呢?是不是觉得有时候信号满格,却还是接不到电话,...
创维安卓系统怎么安装,享受智能... 你家的创维电视是不是最近有点儿不给力,想要给它来个升级,让它焕发新生呢?那就得给它装个安卓系统啦!别...
中兴刷原生安卓系统,原生安卓系... 亲爱的读者们,你是否厌倦了那些千篇一律的安卓系统,想要给你的手机来点新鲜感?今天,就让我带你一起探索...
云系统与安卓系统软件,构建智能... 你有没有想过,你的手机里那些神奇的软件,其实都是靠云系统和安卓系统软件的默契配合才变得如此强大呢?想...
如何禁止安卓系统联网,全方位操... 你有没有想过,你的安卓手机其实是个小宇宙,里面藏着无数的秘密和信息?但是,你知道吗?有时候,这些信息...
a安卓系统不兼容,揭秘a设备的... 最近是不是发现你的安卓手机有些不对劲?比如,某个APP突然罢工了,再比如,你下载了一个新游戏,结果发...
安卓系统刷固件教程,解锁设备潜... 你有没有想过,你的安卓手机其实就像一个隐藏着无限可能的宝藏呢?没错,就是那个你每天不离手的宝贝。今天...
电脑系统安卓界面,功能与美学的... 你有没有发现,现在手机和电脑的界面越来越像了呢?没错,就是那个我们每天都要打交道的好伙伴——安卓界面...
吃鸡王座安卓系统,登顶吃鸡巅峰 你有没有想过,在手机游戏中,谁才是真正的“吃鸡王座”呢?今天,就让我带你一探究竟,看看安卓系统上的那...
安卓点名系统下载,安卓点名系统... 你有没有想过,在繁忙的学习生活中,有没有一种神奇的工具,能让你轻松管理课堂纪律,还能让点名变得如此有...
手机安装通用安卓系统,引领智能... 你有没有想过,为什么你的手机可以安装那么多好玩的应用?秘密就在于它搭载了通用安卓系统!想象一个系统就...
安卓系统仿真器,功能与操作指南 你有没有想过,在电脑上也能玩安卓游戏?没错,这就是安卓系统仿真器的神奇之处!想象你坐在电脑前,手握鼠...
安卓系统可以刷街机,畅享虚拟游... 你知道吗?现在用安卓系统刷街机,简直就像变魔术一样神奇!没错,就是那种让你仿佛穿越回童年,手握游戏杆...
安卓系统画画软件画笔,绘制无限... 你有没有发现,手机里的画画软件越来越丰富啦?尤其是安卓系统上的那些,简直让人眼花缭乱。今天,就让我带...
安卓系统垃圾和缓存,提升使用体... 手机里的安卓系统是不是越来越慢了?是不是觉得打开一个应用都要等半天?别急,今天就来跟你聊聊安卓系统里...
安卓系统图片转入苹果,轻松实现... 你是不是也有过这样的烦恼?手机里存了好多珍贵的照片,突然想换手机,却发现安卓系统的照片怎么也弄不到苹...
华为matebooke装安卓系... 你有没有想过,你的华为MateBook也能装上安卓系统呢?没错,就是那个我们平时手机上用的安卓系统!...