leetcode357- 2812. 找出最安全路径

news/2025/3/19 21:36:19/

这个题比较经典,可以用多个算法来求解,分别给出各个算法的求解方法,主要是分为第一部分的多源BFS求每个位置的距离和第二部分求(0,0)到(n-1,n-1)的最短路径(可以用多种方法求)

目录

  • 多源BFS
  • 求最短路径
    • 枚举安全系数判断是否可行
      • 枚举安全系数
      • 路径是否存在

多源BFS

首先是要求得每个点距离最近的小偷所在位置的距离长度:
暴力枚举每个小偷所在位置,更新所有点到该小偷位置的距离,数据量为400,假设每个位置都有小偷,小偷数量达到400*400,再加上枚举每个位置,最后的复杂度为O(400 * 400 * 400 * 400),即O(n^4)会超时;
多源BFS求距离:多源BFS

// 以所有小偷为起点进行多源 bfsmemset(dis, -1, sizeof(dis));for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) if (grid[i][j] == 1) {q.push(pii(i, j));dis[i][j] = 0;}while (!q.empty()) {pii p = q.front(); q.pop();int i = p.first, j = p.second;for (int k = 0; k < 4; k++) {int ii = i + dir[k][0], jj = j + dir[k][1];if (ii < 0 || jj < 0 || ii >= n || jj >= m || dis[ii][jj] >= 0) continue;q.push(pii(ii, jj));dis[ii][jj] = dis[i][j] + 1;}}

求最短路径

枚举安全系数判断是否可行

枚举答案看是否存在满足答案的路径。
这个思路采用逆向思维方式,不是枚举最短路径判断安全系数,而是枚举安全系数判断对应的最短路径是否存在,也是分为两部分,一部分是如何枚举安全系数,另一部分是如何判断只经过安全系数为lim并且连通起点到终点的路径是否存在。
枚举路径中安全系数(经过的格子的最小值)可以是哪些,相当于枚举只经过安全系数为lim的路径,路径中经过的格子安全系数全都大于等于lim,能否从起点到达终点;然后让这个lim尽可能地大。

枚举安全系数

  1. 可以直接从最大的开始枚举,找到一个符合条件的就可以结束了,O(n)
//直接从大到小枚举for(int i=min(dis[0][0],dis[n-1][m-1]);i>=0;i--){if(check(i)) return i;}
  1. 二分枚举, O(logn) 【最小值最大或者是最大值最小问题】
//二分int l=0,r=min(dis[0][0],dis[n-1][m-1]);while(l<r){int mid=(l+r+1)>>1;if(check(mid)) l=mid;else r=mid-1;}

路径是否存在

判断路径上的安全系数为lim,也就是之前求出来的所有节点的值大于等于lim的连接起点到终点的路径是否存在,有多种方法,bfs,dfs,并查集,只要判断起点和终点连通就行。

  1. BFS
    bfs检查时间,每个位置处遍历一次,复杂度为O(n^2)
    //通过一次bfs,检查能否只经过安全系数大于等于lim的格子,从左上角走到右下角bool check(int lim){q.push({0,0});memset(visited, 0, sizeof(visited));visited[0][0]=true;while(!q.empty()){pii p = q.front(); q.pop();int i = p.first, j = p.second;for (int k = 0; k < 4; k++) {int ii = i + dir[k][0], jj = j + dir[k][1];if (ii < 0 || jj < 0 || ii >= n || jj >= m || dis[ii][jj]<lim ||visited[ii][jj]) continue;q.push(pii(ii, jj));visited[ii][jj]=true;}}return visited[n-1][n-1];}
  1. DFS
    深搜不行,因为涉及到回溯,导致每个节点可能访问多次,导致深搜的时间复杂度无法控制在O(n^2)内,会超时。

  2. 并查集判断(0,0)和(n-1,n-1)是否连通

   int find(int x){if(p[x]==x) return x;return p[x]=find(p[x]);}//并差集判断bool check(int lim){//初始化并查集每个元素是自己,将二维的数组拉成一维的int x=0;for(int i=0;i<n;i++){for(int j=0;j<m;j++){p[x]=x;x++; }}//将每个节点与周围节点合并for(int i=0;i<n;i++){for(int j=0;j<m;j++){if(dis[i][j]<lim) continue;int a=find(i*n+j);for (int k = 0; k < 4; k++) {int ii = i + dir[k][0], jj = j + dir[k][1];if (ii < 0 || jj < 0 || ii >= n || jj >= m || dis[ii][jj]<lim ) continue;int b =find(ii*n+jj);if(a!=b)  p[b]=a;  //合并}}}return find(0)==find(n*n-1) ;}

http://www.ppmy.cn/news/1021548.html

相关文章

任意文件上传漏洞详解与防护

任意文件上传漏洞是一种常见的网络安全问题&#xff0c;它允许攻击者上传并执行恶意文件&#xff0c;从而获取或破坏系统数据。本文将详细介绍这种漏洞的原理、攻击方式、检测方法以及防御措施。 一、任意文件上传漏洞原理 任意文件上传漏洞&#xff0c;通常发生在应用程序接受…

26.Netty源码之ThreadLocal

highlight: arduino-light JDK ThreadLocal 如果你需要变量在多线程之间隔离&#xff0c;或者在同线程内的类和方法中共享&#xff0c;那么 ThreadLocal 大显身手的时候就到了。ThreadLocal 可以理解为线程本地变量&#xff0c;它是 Java 并发编程中非常重要的一个类。 ThreadL…

第十六章、【Linux】程序管理与SELinux初探

16.1 什么是程序 &#xff08;process&#xff09; 在Linux 系统当中&#xff1a;“触发任何一个事件时&#xff0c;系统都会将他定义成为一个程序&#xff0c;并且给予这个程序一个 ID &#xff0c;称为 PID&#xff0c;同时依据启发这个程序的使用者与相关属性关系&#xff…

《合成孔径雷达成像算法与实现》Figure3.7

代码复现如下&#xff1a; clc clear all close all%参数设置 TBP 100; %时间带宽积 T 10e-6; %脉冲持续时间%参数计算 B TBP/T; …

GOLANG进阶 之 接口(interface) 与 管道(channel)

好久没有跟新过文章了&#xff0c;小编最近有点忙&#xff0c;写文章的频率下降了许多&#xff0c;但是还是会持续跟新的&#xff0c;希望关注的同学仔细学习。 首先讲一下接口具体是个啥&#xff1f;小白可以结合官方定义和小编自己的理解共同学习下 官方解释&#xff1a;接口…

uniapp开发小程序-分包(微信错误码:800051)

在使用uniapp开发小程序时&#xff0c;上传的时候因为文件过大&#xff0c;显示上传失败。 以下是开发过程中遇到的问题及解决方法&#xff1a; 1. 问题一&#xff1a;因为文件过大&#xff0c;显示上传失败 ①尝试过把本地使用的图片压缩到最小&#xff1b; ②把图片转换为网…

内网隧道—HTTP\DNS\ICMP

本文仅限于安全研究和学习&#xff0c;用户承担因使用此工具而导致的所有法律和相关责任&#xff01; 作者不承担任何法律和相关责任&#xff01; HTTP隧道 Neo-reGeorg Neo-reGeorg 是一个旨在积极重构 reGeorg 的项目&#xff0c;目的是&#xff1a; 提高可用性&#xff0…

什么是IMAP协议?

IMAP&#xff08;Internet Message Access Protocol&#xff09;是一个应用层协议&#xff0c;用于访问和管理存储在远程服务器上的电子邮件。相比于POP3&#xff0c;IMAP提供了更加丰富的功能&#xff0c;特别适用于需要在多台设备上访问电子邮件的用户。以下是关于IMAP的详细…