[leetcode]1631. 最小体力消耗路径(bool类型dfs+二分答案/记忆化剪枝/并查集Kruskal思想)

news2025/3/25 3:47:45

题目链接

题意

给定 n × m n\times m n×m地图 要从(1,1) 走到 (n,m)
定义高度绝对差为四联通意义下相邻的两个点高度的绝对值之差
定义路径的体力值为整条路径上 所有高度绝对差的max
求所有路径中 最小的路径体力值是多少

方法1

这是我一开始自己写的记忆化剪枝
比较暴力 时间复杂度很高 但是能勉强通过

思路

dfs枚举每条路径 对ans取min
但是会超时 那么加上记忆化剪枝

Code

void cmax(int &a,int b){a=max(a,b);};
void cmin(int &a,int b){a=min(a,b);};
const int N=110;
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
int g[N][N],dp[N][N];//dp表示从(1,1)走到(i,j)的最小体力值
bool vis[N][N];
int n,m;

class Solution {
public:
    int ans=0x3f3f3f3f;//ans必须定义在类内部 因为定义在全局会被上一个测试用例修改
    int minimumEffortPath(vector<vector<int>>& heights) {
        n=heights.size(),m=heights[0].size();
        memset(dp,0x3f,sizeof dp);

        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                g[i+1][j+1]=heights[i][j];
            }
        }

        vis[1][1]=1;
        dfs(1,1,0);

        return ans;
    }

    void dfs(int x,int y,int res){
        if(res>ans) return;
        if(x==n&&y==m){
            cmin(ans,res);
            return;
        }

        for(int i=0;i<4;i++){
            int tx=x+dx[i],ty=y+dy[i];
            if(tx<1||tx>n||ty<1||ty>m||vis[tx][ty]) continue;

            int now=max(abs(g[tx][ty]-g[x][y]),res);

            if(dp[tx][ty]<=now) continue;
            //如果从(tx,ty)这个点已经搜过了 
            //并且之前存的比当前搜的更优 那么就放弃当前这个点
            dp[tx][ty]=now;//当前更优 
         
            vis[tx][ty]=1;
            dfs(tx,ty,now);
            vis[tx][ty]=0;
        }
    }   
};

方法2

思路

最大值最小化 ->二分答案
对路径体力值二分 每次check就是dfs一下能不能在这个高度绝对差不超过mid 的情况下走到终点

Code

#define pii pair<int,int>
#define ar2 array<int,2>
#define ar3 array<int,3>
#define ar4 array<int,4>
#define endl '\n'
void cmax(int &a,int b){a=max(a,b);};
void cmin(int &a,int b){a=min(a,b);};
const int N=110,MOD=1e9+7,INF=0x3f3f3f3f;const long long LINF=LLONG_MAX;const double eps=1e-6;
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
int n,m,g[N][N];
bool vis[N][N];

bool dfs(int x,int y,int k){
    if(x==n&&y==m) return 1;

    for(int i=0;i<4;i++){
        int tx=x+dx[i],ty=y+dy[i];

        if(tx<1||tx>n||ty<1||ty>m||vis[tx][ty]) continue;
        
        int d=abs(g[x][y]-g[tx][ty]);
        if(d<=k){
            vis[tx][ty]=1;
            bool flag=dfs(tx,ty,k);
            if(flag) return 1;
        }
    }
    return 0;
}

class Solution {
public:
    int minimumEffortPath(vector<vector<int>>& heights) {
        n=heights.size(),m=heights[0].size();
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                g[i+1][j+1]=heights[i][j];
            }
        }

        int l=-1,r=1e6+1;
        while(l+1!=r){
            int mid =l+r>>1;
            memset(vis,0,sizeof vis);
            vis[1][1]=1;
            if(dfs(1,1,mid)) r=mid;
            else l=mid;
        }

        return r;
    }
};

实现细节

  • 每次二分要初始化vis数组 并且注意要把起点设为true
  • 重点看bool类型dfs的实现
    • bool dfs(int x,int y,int k)表示从 (x,y)出发 以k为限制能否到达终点
    • 与常见的dfs枚举路径方案不同 这里不需要枚举全部方案 而是只需要找到一个方案能够到达终点就可以
    • 不需要回溯 把vis[tx][ty]=0 因为一旦这个点可以走(从(x,y)到(tx,ty)不超过k到限制) 那么就会被标记为true 然后dfs往下走
    • 如果从(tx,ty)不能到终点 那么dfs会返回false 所以这个点就没有价值了 不需要回溯 如果标记回去 从别的点再次走到这个点是没有意义的 这个点已经搜过了 不可能走到终点
    • 如果dfs从(tx,ty)往下搜 能到终点 就立刻返回true 如果四联通都走了一遍也没return true 那么说明不行 就return false

方法3

思路

Kruskal的思想
把每条边存下来 按边权排序
用并查集维护 一旦起点和终点在一个联通块内 就返回此时的边权(因为排序过了 一定是最大的边权)


这里不需要关心每一步具体是怎么走的
只需要维护每个点的联通关系即可 只要起点和终点联通 就代表一条完整的路径出现了 这个思路太妙了 实现起来很快

Code

void cmax(int &a,int b){a=max(a,b);};
void cmin(int &a,int b){a=min(a,b);};
const int N=110;
int p[N*N];
int n,m;

int find(int x){
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}

struct node{
    int w,u,v;
};

class Solution {
public:
    int minimumEffortPath(vector<vector<int>>& g) {
        n=g.size(),m=g[0].size();

        for(int i=0;i<=n*m;i++) p[i]=i;

        //建图
        vector<node>edges;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                int id=i*m+j;

                if(i>0){
                    edges.push_back((node){abs(g[i-1][j]-g[i][j]),id-m,id});
                }
                if(j>0){
                    edges.push_back((node){abs(g[i][j-1]-g[i][j]),id-1,id});
                }
            }
        }

        sort(edges.begin(),edges.end(),[](const auto& e1,const auto& e2){
            return e1.w<e2.w;
        });

        int ans=0;
        for(auto[w,u,v]:edges){
            int uu=find(u),vv=find(v);
            p[vv]=uu;//不要写成uu=p[vv];

            if(find(0)==find(n*m-1)){
                ans=w;
                break;
            }
        }
        return ans;
    }
   
};

实现细节

关键是在建图
两重循环遍历 每个点都跟他上面以及左边的点建边(如果有的话)
这样就很方便的 不重不漏地把所有的边都建起来了
存边的时候节点编号做一个简单的状态压缩即可

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

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

相关文章

磁盘清理工具-TreeSize Free介绍

TreeSizeFree是一个磁盘空间管理工具&#xff0c;主要用于分析磁盘使用情况&#xff0c;帮助用户找到占用空间大的文件和文件夹: 特点&#xff1a;按大小排序&#xff1a;快速找到占用空间最大的文件或文件夹 一般可以删除: 扫描 C:\Users\XXX\AppData\Local\Temp 或 C:\Window…

c#知识点补充2

1.非静态类能否调用静态方法可以 2.对string类型扩展方法&#xff0c;如何进行 类用静态类&#xff0c;参数是this 调用如下 3.out的用法 一定要给a赋值 这种写法不行 这样才行 4.匿名类 5.委托的使用 无论是匿名委托&#xff0c;还是具命委托&#xff0c;委托实例化后一定要…

力扣45.跳跃游戏

45. 跳跃游戏 II - 力扣&#xff08;LeetCode&#xff09; 代码区&#xff1a; #include<vector> class Solution {public:int jump(vector<int>& nums) {int ans[10005] ;memset(ans,1e4,sizeof(ans));ans[0]0;for(int i0;i<nums.size();i){for(int j1;j…

MacOS安装 nextcloud 的 Virtual File System

需求 在Mac上安装next cloud实现类似 OneDrive 那样&#xff0c;文件直接保存在服务器&#xff0c;需要再下载到本地。 方法 在 官网下载Download for desktop&#xff0c;注意要下对版本&#xff0c;千万别下 Mac OS默认的那个。 安装了登录在配置过程中千万不要设置任何同…

C/C++蓝桥杯算法真题打卡(Day6)

一、P8615 [蓝桥杯 2014 国 C] 拼接平方数 - 洛谷 方法一&#xff1a;算法代码&#xff08;字符串分割法&#xff09; #include<bits/stdc.h> // 包含标准库中的所有头文件&#xff0c;方便编程 using namespace std; // 使用标准命名空间&#xff0c;避免每次调用…

ORACLE RAC ASM双存储架构下存储部分LUN异常的处理

早上接到用户电话&#xff0c;出现有表空间不足的告警&#xff0c;事实上此环境经常巡检并且有告警系统&#xff0c;一开始就带着有所疑惑的心理&#xff0c;结果同事在扩大表空间时&#xff0c;遇到报错 ORA-15401/ORA-17505,提示ASM空间满了&#xff1a; ALERT日志&#xff1…

others-rustdesk远程

title: others-rustdesk远程 categories: Others tags: [others, 远程] date: 2025-03-19 10:19:34 comments: false mathjax: true toc: true others-rustdesk远程, 替代 todesk 的解决方案 前篇 官方 服务器 - https://rustdesk.com/docs/zh-cn/self-host/rustdesk-server-o…

C++基础 [八] - list的使用与模拟实现

目录 list的介绍 List的迭代器失效问题 List中sort的效率测试 list 容器的模拟实现思想 模块分析 作用分析 list_node类设计 list 的迭代器类设计 迭代器类--存在的意义 迭代器类--模拟实现 模板参数 和 成员变量 构造函数 * 运算符的重载 运算符的重载 -- 运…

使用excel.EasyExcel实现导出有自定义样式模板的excel数据文件,粘贴即用!!!

客户要求导出的excel文件是有好看格式的&#xff0c;当然本文举例模板文件比较简单&#xff0c;内容丰富的模板可以自行设置&#xff0c;话不多说&#xff0c;第一步设置一个"好看"的excel文件模板 上面要注意的地方是{.变量名} &#xff0c;这里的变量名对应的就是…

Spring Boot 集成 Elasticsearch怎样在不启动es的情况下正常启动服务

解释 在spingboot 集成es客户端后&#xff0c;每当服务启动时&#xff0c;服务默认都会查看es中是否已经创建了对应的索引&#xff0c;如果没有索引则创建。基于上面的规则我们可以通过配置不自动创建索引来达到在没有es服务的情况下正常启动服务。 解决办法 在entity类的Docu…

JVM常见概念之条件移动

问题 当我们有分支频率数据时&#xff0c;有什么有趣的技巧可以做吗&#xff1f;什么是条件移动&#xff1f; 基础知识 如果您需要在来自一个分支的两个结果之间进行选择&#xff0c;那么您可以在 ISA 级别做两件不同的事情。 首先&#xff0c;你可以创建一个分支&#xff…

Android AI ChatBot-v1.6.3-28-开心版[免登录使用GPT-4o和DeepSeek]

Android AI ChatBot- 链接&#xff1a;https://pan.xunlei.com/s/VOLi1Ua071S6QZBGixcVL5eeA1?pwdp3tt# 免登录使用GPT-4o和DeepSeek

集成学习(上):Bagging集成方法

一、什么是集成学习&#xff1f; 在机器学习的世界里&#xff0c;没有哪个模型是完美无缺的。就像古希腊神话中的"盲人摸象"&#xff0c;单个模型往往只能捕捉到数据特征的某个侧面。但当我们把多个模型的智慧集合起来&#xff0c;就能像拼图一样还原出完整的真相&a…

DeepSeek R1 本地部署指南 (3) - 更换本地部署模型 Windows/macOS 通用

0.准备 完成 Windows 或 macOS 安装&#xff1a; DeepSeek R1 本地部署指南 (1) - Windows 本地部署-CSDN博客 DeepSeek R1 本地部署指南 (2) - macOS 本地部署-CSDN博客 以下内容 Windows 和 macOS 命令执行相同&#xff1a; Windows 管理员启动&#xff1a;命令提示符 CMD ma…

【TI MSPM0】Timer学习

一、计数器 加法计数器&#xff1a;每进入一个脉冲&#xff0c;就加一减法计算器&#xff1a;每进入一个脉冲&#xff0c;就减一 当计数器减到0&#xff0c;触发中断 1.最短计时时间 当时钟周期为1khz时&#xff0c;最短计时时间为1ms&#xff0c;最长计时时间为65535ms 当时…

Windows部署deepseek R1训练数据后通过AnythingLLM当服务器创建问答页面

如果要了解Windows部署Ollama 、deepseek R1请看我上一篇内容。 这是接上一篇的。 AnythingLLM是一个开源的全栈AI客户端&#xff0c;支持本地部署和API集成。它可以将任何文档或内容转化为上下文&#xff0c;供各种语言模型&#xff08;LLM&#xff09;在对话中使用。以下是…

信奥赛CSP-J复赛集训(模拟算法专题)(27):P5016 [NOIP 2018 普及组] 龙虎斗

信奥赛CSP-J复赛集训(模拟算法专题)(27):P5016 [NOIP 2018 普及组] 龙虎斗 题目背景 NOIP2018 普及组 T2 题目描述 轩轩和凯凯正在玩一款叫《龙虎斗》的游戏,游戏的棋盘是一条线段,线段上有 n n n 个兵营(自左至右编号 1 ∼ n 1 \sim n 1∼n),相邻编号的兵营之间…

多模态大模型常见问题

1.视觉编码器和 LLM 连接时&#xff0c;使用 BLIP2中 Q-Former那种复杂的 Adaptor 好还是 LLaVA中简单的 MLP 好&#xff0c;说说各自的优缺点&#xff1f; Q-Former&#xff08;BLIP2&#xff09;&#xff1a; 优点&#xff1a;Q-Former 通过查询机制有效融合了视觉和语言特征…

SpringBoot项目实战(初级)

目录 一、数据库搭建 二、代码开发 1.pom.xml 2.thymeleaf模块处理的配置类 3.application配置文件 4.配置&#xff08;在启动类中&#xff09; 5.编写数据层 ②编写dao层 ③编写service层 接口 实现类 注意 补充&#xff08;注入的3个注解&#xff09; 1.AutoWir…

计算机网络——总结

01. 网络的发展及体系结构 网络演进历程 从1969年ARPANET的4个节点发展到如今覆盖全球的互联网&#xff0c;网络技术经历了电路交换到分组交换、有线连接到无线覆盖的革命性变革。5G时代的到来使得网络传输速度突破10Gbps&#xff0c;物联网设备数量突破百亿级别。 网络体系…