BFS——多源BFS+双端队列BFS

173. 矩阵距离(173. 矩阵距离 - AcWing题库)

思路:这题和多源最短路还是有一些区别的,相当于求一个点到距离它最近的一个终点的距离,其实我们可以反着来看,将终点视为起点,然后加一个虚拟起点,将这些起点到虚拟起点的距离设为0,那么我们实际上要求的就是所有点到虚拟起点的最短路。这里这个虚拟起点并不需要真实存在,我们将所有起点同时放进队列即可。

#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> pii;
pii q[1000010];
int d[1010][1010];
char s[1010][1010];
int n,m,hh,tt;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
void bfs()
{memset(d,-1,sizeof d);hh=tt=0;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(s[i][j]=='1'){d[i][j]=0;q[tt++]={i,j};}}}while(hh<tt){auto t=q[hh++];for(int i=0;i<4;i++){int nx=t.x+dx[i],ny=t.y+dy[i];if(nx<1||nx>n||ny<1||ny>m) continue;if(d[nx][ny]!=-1) continue;d[nx][ny]=d[t.x][t.y]+1;q[tt++]={nx,ny};}}
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%s",s[i]+1);bfs();for(int i=1;i<=n;i++){for(int j=1;j<=m;j++)printf("%d ",d[i][j]);printf("\n");}
}

 1107. 魔板(1107. 魔板 - AcWing题库)

 

思路:这道题和之前遇到的题目不同的地方就在于之前的是在一张图中进行查找,而这里则是将每一张图视为一个状态。求一个状态到另一个状态的最小步数。所以要解决的第一个问题就是如何存状态,我们可以将二维的矩阵转化成一个字符串,然后在操作的时候再转化回去,将操作之后的状态再转化成一个字符串。另外我们再来看看这里要求的量,一个是求最小的操作次数,另一个是求字典序最小的操作序列,这里为了得到字典序最小的操作序列,实际上我们按照ABC的顺序来更新,再将更新到的序列放入队列即可。根据队列的单调性可知,这样得到的终点操作数一定是最小的。为了得到操作方案,我们只用记录一下每一步是由谁转化而来的即可。

#include<bits/stdc++.h>
using namespace std;
char g[2][4];
unordered_map<string,int>d;
unordered_map<string,pair<char,string>>pre;
void tog(string state)
{for(int i=0;i<4;i++) g[0][i] = state[i];for(int i=7,j=0;j<4;i--,j++) g[1][j]=state[i];}
string tos()
{string res;for(int i=0;i<4;i++) res += g[0][i];for(int i=3;i>=0;i--) res+=g[1][i];return res;
}
string move0(string state)
{tog(state);for(int i=0;i<4;i++) swap(g[0][i],g[1][i]);return tos();
}
string move1(string state)
{tog(state);char a=g[0][3],b=g[1][3];for(int i=3;i>0;i--) {g[0][i]=g[0][i-1];g[1][i]=g[1][i-1];}g[0][0]=a,g[1][0]=b;return tos();
}
string move2(string state)
{tog(state);char a=g[0][1];g[0][1]=g[1][1];g[1][1]=g[1][2];g[1][2]=g[0][2];g[0][2]=a;return tos();
}
int bfs(string state,string end)
{if(state==end) return 0;queue<string>q;q.push(state);d[state]=0;while(q.size()){auto t=q.front();q.pop();string m[3];m[0]=move0(t);m[1]=move1(t);m[2]=move2(t);for(int i=0;i<3;i++)if(!d.count(m[i])){d[m[i]]=d[t]+1;pre[m[i]]={'A'+i,t};q.push(m[i]);if(m[i]==end) return d[end];}}return -1;
}
int main()
{int x;string s,e;for(int i=0;i<8;i++){cin>>x;e+=char(x+'0');}s="12345678";int step=bfs(s,e);cout<<step<<endl;string res;while(e!=s){res += pre[e].first;e=pre[e].second;}reverse(res.begin(),res.end());if(step>0)cout<<res;
}

 对了,一定要注意一下,是从谁到谁。‘

175. 电路维修(175. 电路维修 - AcWing题库)

 思路:

按照这个图就很明显,每个点只有四个点是可以到的,那么我们就来思考一下如果这四个方格中的线的路径与给定的相同,那么显然就不用操作,否则就要进行一次操作,所以我们到下一个点的边权可能是1,也可能是0,为了保证队列的单调性就不能直接放队尾,那么我们可以直接令为0的时候从队头插入,为1的时候从队尾插入,那么可以用双端队列实现。

然后再分析一下点的格子的关系,因为我们给的是每个格子的状态,但我们实际更新的状态是各个点的状态。

 

那么就出来了,某点将要转移到的四个点

dx[]={-1,-1,1,1}

dy[]={-1,1,-1,1}

用到的格子:

ix[]={-1,-1,0,0}

iy[]={-1,0,-1,0}

需要的状态\,/,\,/,记得转义一下。

另外注意这里的边权有0,所以一个点并不是被放入队列的时候最短,而是出队的时候最短,因为它还能被更新。这里也可以用优先队列,但是由于只有0和1两种边长,所以我们直接一种放队头一种放队尾即可,因为当前被取出来的一定是最短的,由它通过0更新的点,一定和它一样也是最短的。另外我们可以发现,能走到的点都是与起点奇偶性相同的点,因为每次移动时,横纵坐标都要发生变化。

#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
char s[600][600];
int n,m;
int d[600][600];
int dx[]={-1,-1,1,1};
int dy[]={-1,1,-1,1};
int ix[]={-1,-1,0,0};
int iy[]={-1,0,-1,0};
int st[600][600];
char op[]={'\\','/','/','\\'};
void bfs()
{memset(d,0x3f,sizeof d);memset(st,0,sizeof st);d[0][0]=0;deque<pair<int,int>>q;q.push_back({0,0});while(q.size()){auto t=q.front();q.pop_front();if(st[t.x][t.y]) continue;st[t.x][t.y]=1;if(t.x==n&&t.y==m) break;for(int i=0;i<4;i++){int nx=t.x+dx[i],ny=t.y+dy[i];if(nx<0||nx>n||ny<0||ny>m)  continue;int opx=t.x+ix[i],opy=t.y+iy[i];if(s[opx][opy]==op[i]) {d[nx][ny]=min(d[nx][ny],d[t.x][t.y]);q.push_front({nx,ny});}else{d[nx][ny]=min(d[nx][ny],d[t.x][t.y]+1);q.push_back({nx,ny});}}}
}
int main()
{int t;scanf("%d",&t);while(t--){scanf("%d%d",&n,&m);for(int i=0;i<n;i++) scanf("%s",s[i]);if((n+m)%2) printf("NO SOLUTION\n"); else{bfs();cout<<d[n][m]<<endl;}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

降维(Dimensionality Reduction)

一、动机一&#xff1a;数据压缩 这节我将开始谈论第二种类型的无监督学习问题&#xff0c;称为降维。有几个原因使我们可能想要做降维&#xff0c;其一是数据压缩&#xff0c;它不仅允许我们压缩数据使用较少的计算机内存或磁盘空间&#xff0c;而且它可以加快我们的学习算法。…

Android Studio非UI线程修改控件——定时器软件

目录 一、UI界面设计 1、UI样式 2、XML代码 二、功能编写 1、定义 2、实现方法 3、功能实现 一、UI界面设计 1、UI样式 2、XML代码 <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android…

vue实现带缩略图的轮播图(vue-awesome-swiper)

demo 请复制打开 https://download.lllomh.com/cliect/#/product/E125504451206525 如点击链接跳转失败请复制网址到浏览器打开 1.引入swiper和vue-awesome-swiper插件 npm install swiper4 --save npm install vue-awesome-swiper3 --save2.在main.js中引入&#xff1a; …

【代码随想录20】669.修剪二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树

目录 669.修剪二叉搜索树题目描述参考代码 108.将有序数组转换为二叉搜索树题目介绍参考代码 538.把二叉搜索树转换为累加树题目描述参考代码 669.修剪二叉搜索树 题目描述 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树…

XGB-1:XGBoost安装及快速上手

XGBoost是“Extreme Gradient Boosting”的缩写&#xff0c;是一种高效的机器学习算法&#xff0c;用于分类、回归和排序问题。它由陈天奇&#xff08;Tianqi Chen&#xff09;在2014年首次提出&#xff0c;并迅速在数据科学竞赛和工业界获得广泛应用。XGBoost基于梯度提升框架…

【Git】01 Git介绍与安装

文章目录 一、版本控制系统二、Git三、Windows安装Git3.1 下载Git3.2 安装3.3 检查 四、Linux安装Git4.1 YUM安装4.2 源码安装 五、配置Git5.1 配置用户名和邮箱5.2 配置级别5.3 查看配置 六、总结 一、版本控制系统 版本控制系统&#xff0c;Version Control System&#xff…

Unity中AssetBundle的打包和分包策略

在Unity中&#xff0c;AssetBundle的打包策略主要是针对资源的整理和分组&#xff0c;以做到即方便管理&#xff0c;又能有效优化资源的加载和内存使用。具体来看包括以下几种常见的策略&#xff1a; 打包资源的预处理&#xff1a;为了减小AssetBundle的大小和数量&#xff0c;…

C语言数据结构之两道OJ题带你走近环形链表

倘若南风知我意 莫将晚霞落黄昏 &#x1f3a5;烟雨长虹&#xff0c;孤鹜齐飞的个人主页 &#x1f525;个人专栏 &#x1f3a5;前期回顾-单链表 目录 环形链表 题目描述# 思路# 代码测试# 环形链表II 题目描述# 思路# 代码测试# 环形链表 题目链接&#xff1a;环形链表 题目…

基于极大似然法和最小二乘法系统参数辨识matlab仿真,包含GUI界面

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 1.极大似然法系统参数辨识 2. 最小二乘法系统参数辨识 5.完整程序 1.程序功能描述 分别对比基于极大似然法的系统参数辨识以及基于最小二乘法的系统参数辨识&#xff0c;输出起参数辨识收敛…

linux中vim的操作

(码字不易&#xff0c;关注一下吧w~~w) 命令模式&#xff1a; 当我们按下esc键时&#xff0c;我们会进入命令模式&#xff1b;当使用vi打开一个文件时也是进入命令模式。 光标移动&#xff1a; 1 保存退出&#xff1a;ZZ 2 代码格式化&#xff1a;ggG 3 光标移动&#xff…

(学习日记)2024.02.01:引用变量 / 默认实参 / 一元作用域运算符 / 函数重载

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

Linux一键部署telegraf 实现Grafana Linux 图形展示

influxd2前言 influxd2 是 InfluxDB 2.x 版本的后台进程,是一个开源的时序数据库平台,用于存储、查询和可视化时间序列数据。它提供了一个强大的查询语言和 API,可以快速而轻松地处理大量的高性能时序数据。 telegraf 是一个开源的代理程序,它可以收集、处理和传输各种不…