天梯题集——紧急救援(Dijkstra+倒序打印分析)

2023-11-19

Dijkstra算法:用于求单源到其他点的最短路径。

紧急救援

题目
该题与 Dijkstra模板题 的不同之处在于该题需要记录更多信息,主要思路从局部最优到整体最优,类似dp的思想。

#include<bits/stdc++.h>
#define maxv 510
#define INF 0x3f3f3f3f
#define ll long long 
using namespace std;

int mp[maxv][maxv];  // 地图
int w[maxv];         // 救援队数量

int dis[maxv];       // dijkstra各点到源点的最近距离
int cnt[maxv];       // 源点到各点最近距离相同的路径条数
int sum[maxv];      // 从源点走到各点可召集的消防员的最大值

int pre[maxv];       // 记录最短路径下城市的上一个城市 
bool flag[maxv];     // 访问标志
 
int M,N,S,D;

//打印 
void path(int k) {
    if(k<0) return;
    path(pre[k]);
    cout<<k;
    if(k!=D) cout<<" "; 
}
 
void dijkstra(int s) {
    fill(dis, dis+M, INF);		//对dis数组进行赋值 
    fill(flag, flag+M, false);
    fill(pre, pre+M, -1);
 
    //初始情况,起点到起点
    dis[s] = 0;
    sum[s]= w[s];
    cnt[s] = 1;
 	
 	//从局部最优到整体最优 
    while(1) {
        int v, Max=INF;
        
        //在所有未被访问的点中找一个距离最近的点作为当前最短路的终点
        for(int u=0; u<M; u++) 
        if(!flag[u] && Max>dis[u]){
			Max = dis[u];
           	v = u;
        }
 
        //如果所有点都起码已经访问过就终止循环
        if(Max==dis[u]) break;

        flag[v] = true;
        //更新路径
        for(int u=0; u<M; u++) {
            if(mp[v][u] == INF)
                continue;
			
			//存在更短路径 
            if(dis[v]+mp[v][u] < dis[u]){
                dis[u] = dis[v]+mp[v][u];
                pre[u] = v;			    //u的上一个城市v
 
                cnt[u] = cnt[v];		//u城市的最短路径数等于v城市的最短路径数 
                sum[u] = sum[v]+w[u];   //u城市的最大消防人数等于最短路径上的消防人员和 
            }
            //最短路径长度相等 
            else if(dis[v]+mp[v][u] == dis[u]){
                cnt[u] += cnt[v];
                
                //从最短路径中维护最大消防人员数量和路径 
                if(sum[v]+w[u] > sum[u]){
                    sum[u] = sum[v]+w[u];
                    pre[u] = v;	
                }
            }
        }
    }
 
    cout<<cnt[D]<<" "<<sum[D]<<endl;
    path(D);	//倒序打印 
    cout<<endl;
    
    return; 
}
 
int main() {
    cin>>M>>N>>S>>D;
 
    for(int i=0; i<M; i++)
    for(int j=0; j<M; j++)
        mp[i][j] = INF;
    
    for(int i=0; i<M; i++)
        cin>>w[i];
 
    for(int i=0; i<N; i++) {
        int a,b;
        cin>>a>>b;
        cin>>mp[a][b];
        mp[b][a] = mp[a][b];
    }
    
    dijkstra(S);
 
    return 0;
}

其中我认为有一点值得思考,为什么要倒序打印?
假如正序存储再正序打印结果会是怎么样的?

//正序存储路径并打印
#include<bits/stdc++.h>
#define maxv 500+8
#define INF 0x3f3f3f3f
#define ll long long 
using namespace std;

int mp[maxv][maxv]; 
int w[maxv];       

int dis[maxv];      
int cnt[maxv];       
int sum[maxv];    

int next[maxv];      
bool flag[maxv]={false};   
 
int M,N,S,D;

//打印 
void path(int k) {
    cout<<k;
    if(k!=D)
		cout<<" ";
	if(k==D) return;
	path(next[k]);
}
 
void dijkstra(int s) {
    fill(dis, dis+M, INF);		
    fill(flag, flag+M, false);
    fill(next, next+M, -1);
 
    dis[s] = 0;
    sum[s]= w[s];
    cnt[s] = 1;
 
	//每个 v 只能改变一次,不能更新
	//不可正序记录路径。 
    while(1) {
        int v, Max=INF;
        
        for(int u=0; u<M; u++) 
        if(!flag[u] && dis[u]<Max){
			Max = dis[u];
           	v = u;
        }
 
        if(Max==INF) break;
        flag[v] = true;
        
        for(int u=0; u<M; u++) {
            if(mp[v][u] == INF||v==u)
                continue;
			
            if(dis[v]+mp[v][u] < dis[u]){
                dis[u] = dis[v]+mp[v][u];
                next[v] = u;			 
 
                cnt[u] = cnt[v];		
                sum[u] = sum[v]+w[u];   
            }
            else if(dis[v]+mp[v][u] == dis[u]){
                cnt[u] += cnt[v];
               
                if(sum[v]+w[u] > sum[u]){
                    sum[u] = sum[v]+w[u];
                    next[v] = u;	
                }
            }
        }
    }
    cout<<cnt[D]<<" "<<sum[D]<<endl;
    path(S);
    cout<<endl;
    
    return; 
}
 
int main() {
    cin>>M>>N>>S>>D;
 
    for(int i=0; i<M; i++)
    for(int j=0; j<M; j++)
        mp[i][j] = INF;
    
    for(int i=0; i<M; i++)
        cin>>w[i];
 
    for(int i=0; i<N; i++) {
        int a,b;
        cin>>a>>b;
        cin>>mp[a][b];
        mp[b][a] = mp[a][b];
    }
    
    dijkstra(S);
 
    return 0;
}

将样例一放在正序打印代码上,结果是错误的。
正序打印:每次确定最佳方案下 v 城市下一个城市。
倒序打印:每次预测最佳方案下哪些城市的下一个城市是 v 城市。

我们不能够在未知其他城市与 D 的距离下,确定 S 城市的下一个城市。
但我们能够通过查找最优方案下提前预测哪些城市的下一个城市是 S。
似乎有点玄,但是很妙…


补充 fill() 函数

//将arr数组中的元素都赋值为 2
#include <bits/stdc++.h>
using namespace std;
int main() 
{
    int arr[10];
    fill(arr, arr + 10, 2);
    return 0;
}

fill() 函数类似于 memset() 函数,但会更加便利。
memset() 函数常用来对数组进行置 0 。
fill() 函数不单可以对数组进行置 0,也能设定为其他数值。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

天梯题集——紧急救援(Dijkstra+倒序打印分析) 的相关文章

随机推荐

  • android- Cause: Unknown command-line option '-X'.

    问题太简单了 直接解决办法 File gt Settings gt Build Execution Deployment gt Compiler 删除Command line options里面的内容 重新gradle 感谢博主 欢迎留言指
  • 全栈之前端

    欢迎关注 全栈工程师修炼指南 公众号 点击 下方卡片 即可关注我哟 设为 星标 每天带你 基础入门 到 进阶实践 再到 放弃学习 花开堪折直须折 莫待无花空折枝 作者主页 https www weiyigeek top 博客 https b
  • 2022面试题汇总

    目录 浏览器下两个页面的通讯都有什么方式 使用css与js做一个九宫格动画 请输出如下的代码打印结果 js如何实现页面地址发生变化 但页面不发生跳转 请用js实现 请用多种方式实现垂直居中 实现的方式越多越好 请实现一个getValue函数
  • 【深度学习】全面直观认识深度神经网络

    01深度学习的精准定义 一类通过多层非线性变换对高复杂性数据建模算法的集合 它的两个非常重要的特征是多层性和非线性 俗称多层非线性变换 所以深度学习要去线性化 为什么呢 因为线性模型存在局限性 任意线性模型得到组合仍然还是线性模型 所以只要
  • Linux如何找回或者重置root用户密码

    欢迎参与个人独立开发的阅时即查web APP公测 请扫码体验 第一个为旧版 第二个为2019年6月版 在Linux这样一个权限管理严格 系统安全性要求高的环境中 根用户 超级用户 root的的密码显得十分重要 但是还是有一些马大哈会忘记自己
  • 【LLM】深入剖析 GOOGLE PALM 2:全面概述

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • 用一维字符数组存放字符串

    一 用一维字符数组存放字符串 1 C语言对字符串的约定 字符串是借助于字符型一维数组来存放的 并规定以字符 0 作为字符串的结束标志 0 作为标志占用存储空间 但不计入串的实际常量 2 C语言中表示字符串常量的约定 虽然c语言中没有字符串数
  • regex_replace()函数的应用与解析

    include
  • lua报错 module 'Module' not found

    这几天学习lua使用require关键字获取自己定义的模块式 发现报没有这个模块文件 询问老师 老师说是因为中文路径问题 的确这个可能会出现问题 但是我修改后还是报这个错误 老师就让我看他的源代码 我确定没写错 所以还是要靠自己来解决了 终
  • 【sql语句基础】——查(select)(合并查询)

    目录 合并查询 单独查询 合并查询 UNION ALL UNION ALL定义 UNION ALL代码示例 UNION ALL查询结果 合并查询 UNION ALL UNION 定义 UNION 代码示例 UNION 查询结果 合并查询 当
  • Android Button 背景高度被拉伸问题

  • Linux音频之ASOC

    参考 https blog csdn net droidphone article details 7165482 1 ASOC简介 ASoC ALSA System on Chip 是建立在标准ALSA驱动层上 为了更好地支持嵌入式处理器
  • 第八章、Linux 磁盘与文件系统管理

    系统管理员很重要的任务之一就是管理好自己的磁盘文件系统 每个分割槽不可太大也不能太小 太大会造成磁盘容量的浪费 太小则会产生文件无法储存的困扰 此外 我们在前面几章谈到的文件权限与属性中 这些权限与属性分别记录在文件系统的哪个区块内 这就得
  • 贝叶斯网络学习

    状态空间搜索 如果按专业点的说法就是将问题求解过程表现为从初始状态到目标状态寻找这个路径的过程 通俗点说 两点之间求一线路 这两点是求解的开始和问题的结果 而这一线路不一定是直线 可以是曲折的 由于求解问题的过程中分枝有很多 主要是求解过程
  • 神经网络——实现MNIST数据集的手写数字识别

    由于官网下载手写数字的数据集较慢 因此提供便捷下载地址如下 手写数字的数据集MNIST下载 https download csdn net download gaoyu1253401563 10891997 数据集包含如下 一 使用小规模数
  • 超级简单!vue解决前后端跨域问题,看完就会

    在Vue中解决前后端跨域问题 需要通过配置和设置代理来实现 配置 在Vue的config目录下的index js文件中 找到devServer选项 在其中添加如下代码 devServer proxy api target http loca
  • mysql my-innodb-heavy-4g.cnf_my-innodb-heavy-4G.cnf 配置文件

    client 客户端配置 port 3306 mysql连接时默认的端口号 socket tmp mysql sock 用于连接mysql mysqld 服务端配置 port 3306 mysql服务默认监听的端口 socket tmp m
  • window opengl

    接口 https www khronos org registry OpenGL api GL
  • 一文吃透KMP算法

    前提 假设我们在字符串 bacbababaabababca 中 搜寻字符串 abababca 是否存在 KMP算法过程 下面就KMP算法的匹配过程进行阐述 step0 在执行匹配之前 先定义几个概念 前缀集合 后缀集合 部分匹配值 前缀集合
  • 天梯题集——紧急救援(Dijkstra+倒序打印分析)

    Dijkstra算法 用于求单源到其他点的最短路径 紧急救援 该题与 Dijkstra模板题 的不同之处在于该题需要记录更多信息 主要思路从局部最优到整体最优 类似dp的思想 include