c/c++蓝桥杯经典编程题100道(22)最短路径问题

devtools/2025/2/21 9:17:20/

最短路径问题

->返回c/c++蓝桥杯经典编程题100道-目录


目录

最短路径问题

一、题型解释

二、例题问题描述

三、C语言实现

解法1:Dijkstra算法(正权图,难度★★)

解法2:Bellman-Ford算法(含负权边,难度★★★)

四、C++实现

解法1:Dijkstra算法(优先队列优化,难度★★☆)

解法2:Floyd-Warshall算法(多源最短路径,难度★★★)

五、总结对比表

六、特殊方法与内置函数补充

1. C++ STL的优先队列

2. 动态规划思想

3. 负权环检测


一、题型解释

最短路径问题是图论中的核心问题,目标是找到图中两点间权重和最小的路径。常见题型:

  1. 单源最短路径:求某一点到其他所有点的最短路径(如Dijkstra、Bellman-Ford算法)。

  2. 多源最短路径:求所有点对之间的最短路径(如Floyd-Warshall算法)。

  3. 特殊场景

    • 含负权边的最短路径(Bellman-Ford)。

    • 含负权环的检测(Bellman-Ford扩展)。

    • 边权为1的图(BFS优化)。


二、例题问题描述

例题1(单源正权图)

  • 输入:图的邻接矩阵,起点为A。

  • 输出:A到各顶点的最短距离(如A→D的最短距离为5)。

例题2(含负权边)

  • 输入:带负权边的图,检测是否存在负权环。

  • 输出:若存在环返回false,否则返回最短路径。

例题3(多源最短路径)

  • 输入:任意两点间的最短距离矩阵。

  • 输出:更新后的最短距离矩阵。


三、C语言实现

解法1:Dijkstra算法(正权图,难度★★)

通俗解释

  • 贪心策略:每次选择当前距离起点最近的节点,逐步扩展最短路径集合。

  • 适用条件:边权非负。

c

#include <stdio.h>
#include <limits.h>#define V 6  // 顶点数int minDistance(int dist[], int visited[]) {int min = INT_MAX, min_index;for (int v = 0; v < V; v++)if (!visited[v] && dist[v] <= min)min = dist[v], min_index = v;return min_index;
}void dijkstra(int graph[V][V], int src) {int dist[V];      // 存储最短距离int visited[V];   // 记录节点是否已处理for (int i = 0; i < V; i++)dist[i] = INT_MAX, visited[i] = 0;dist[src] = 0;  // 起点到自身距离为0for (int count = 0; count < V - 1; count++) {int u = minDistance(dist, visited); // 选取未处理的最小距离节点visited[u] = 1;// 更新相邻节点的距离for (int v = 0; v < V; v++)if (!visited[v] && graph[u][v] && dist[u] != INT_MAX &&dist[u] + graph[u][v] < dist[v])dist[v] = dist[u] + graph[u][v];}// 输出结果printf("顶点\t距离\n");for (int i = 0; i < V; i++)printf("%d\t%d\n", i, dist[i]);
}int main() {int graph[V][V] = {{0, 4, 0, 0, 0, 0},{4, 0, 8, 0, 0, 0},{0, 8, 0, 7, 0, 4},{0, 0, 7, 0, 9, 14},{0, 0, 0, 9, 0, 10},{0, 0, 4, 14, 10, 0}};dijkstra(graph, 0);return 0;
}

代码逻辑

  1. 初始化:距离数组dist设为无穷大,起点距离为0。

  2. 循环处理:每次选择未访问的最小距离节点,更新其邻居的距离。

  3. 时间复杂度:O(V²),适合稠密图。


解法2:Bellman-Ford算法(含负权边,难度★★★)

通俗解释

  • 松弛操作:通过多次迭代所有边,逐步逼近最短路径。

  • 附加功能:可检测负权环。

c

#include <stdio.h>
#include <limits.h>#define E 8  // 边数
#define V 5  // 顶点数struct Edge {int src, dest, weight;
};void bellmanFord(struct Edge edges[], int src) {int dist[V];for (int i = 0; i < V; i++)dist[i] = INT_MAX;dist[src] = 0;// 松弛所有边V-1次for (int i = 1; i <= V - 1; i++) {for (int j = 0; j < E; j++) {int u = edges[j].src;int v = edges[j].dest;int w = edges[j].weight;if (dist[u] != INT_MAX && dist[u] + w < dist[v])dist[v] = dist[u] + w;}}// 检测负权环for (int j = 0; j < E; j++) {int u = edges[j].src;int v = edges[j].dest;int w = edges[j].weight;if (dist[u] != INT_MAX && dist[u] + w < dist[v]) {printf("图中存在负权环!\n");return;}}// 输出结果printf("顶点\t距离\n");for (int i = 0; i < V; i++)printf("%d\t%d\n", i, dist[i]);
}int main() {struct Edge edges[E] = {{0, 1, -1}, {0, 2, 4}, {1, 2, 3},{1, 3, 2}, {1, 4, 2}, {3, 2, 5},{3, 1, 1}, {4, 3, -3}};bellmanFord(edges, 0);return 0;
}

代码逻辑

  1. 初始化:所有距离设为无穷大,起点为0。

  2. 松弛操作:进行V-1轮边遍历更新距离。

  3. 负权环检测:若第V轮仍有更新,说明存在负权环。

  4. 时间复杂度:O(VE),适合稀疏图。


四、C++实现

解法1:Dijkstra算法(优先队列优化,难度★★☆)

通俗解释

  • 使用优先队列快速获取最小距离节点,时间复杂度优化至O((V+E)logV)。

cpp

#include <iostream>
#include <vector>
#include <queue>
#include <climits>
using namespace std;typedef pair<int, int> pii; // {距离, 节点}void dijkstra(vector<vector<pii>> &graph, int src) {int V = graph.size();vector<int> dist(V, INT_MAX);priority_queue<pii, vector<pii>, greater<pii>> pq;dist[src] = 0;pq.push({0, src});while (!pq.empty()) {int u = pq.top().second;int d = pq.top().first;pq.pop();if (d > dist[u]) continue; // 跳过旧数据for (auto &edge : graph[u]) {int v = edge.first;int w = edge.second;if (dist[u] + w < dist[v]) {dist[v] = dist[u] + w;pq.push({dist[v], v});}}}cout << "顶点\t距离" << endl;for (int i = 0; i < V; i++)cout << i << "\t" << dist[i] << endl;
}int main() {int V = 5;vector<vector<pii>> graph(V);graph[0].push_back({1, 4});graph[0].push_back({2, 1});graph[1].push_back({3, 2});graph[2].push_back({1, 1});graph[2].push_back({3, 5});graph[3].push_back({4, 3});dijkstra(graph, 0);return 0;
}

代码逻辑

  1. 优先队列:存储{距离, 节点},自动按距离排序。

  2. 懒惰删除:当队列中的距离大于记录的距离时跳过。

  3. STL使用vector存邻接表,priority_queue实现最小堆。


解法2:Floyd-Warshall算法(多源最短路径,难度★★★)

通俗解释

  • 动态规划:通过中间节点逐步优化所有点对的最短路径。

cpp

#include <iostream>
#include <vector>
using namespace std;#define INF INT_MAXvoid floydWarshall(vector<vector<int>> &graph) {int V = graph.size();vector<vector<int>> dist = graph;for (int k = 0; k < V; k++)for (int i = 0; i < V; i++)for (int j = 0; j < V; j++)if (dist[i][k] != INF && dist[k][j] != INF)dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);// 输出结果cout << "最短路径矩阵:" << endl;for (int i = 0; i < V; i++) {for (int j = 0; j < V; j++)cout << (dist[i][j] == INF ? "INF" : to_string(dist[i][j])) << "\t";cout << endl;}
}int main() {vector<vector<int>> graph = {{0, 5, INF, 10},{INF, 0, 3, INF},{INF, INF, 0, 1},{INF, INF, INF, 0}};floydWarshall(graph);return 0;
}

代码逻辑

  1. 初始化距离矩阵:直接复制图的邻接矩阵。

  2. 三重循环:依次考虑每个中间节点k,更新所有i→j路径。

  3. 时间复杂度:O(V³),适合小规模图。


五、总结对比表

算法时间复杂度空间复杂度适用场景
DijkstraO((V+E)logV)O(V)正权图单源最短路径
Bellman-FordO(VE)O(V)含负权边的单源最短路径
Floyd-WarshallO(V³)O(V²)多源最短路径

六、特殊方法与内置函数补充

1. C++ STL的优先队列

  • 作用:快速获取最小元素,用于优化Dijkstra算法

  • 语法priority_queue<T, Container, Compare>,需头文件<queue>

2. 动态规划思想

  • Floyd-Warshall核心dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])

3. 负权环检测

  • Bellman-Ford扩展:若第V次迭代仍有更新,则存在负权环。

->返回c/c++蓝桥杯经典编程题100道-目录


http://www.ppmy.cn/devtools/160305.html

相关文章

Webpack 基础入门

一、Webpack 是什么 Webpack 是一款现代 JavaScript 应用程序的静态模块打包工具。在 Web 开发中&#xff0c;我们的项目会包含各种类型的文件&#xff0c;如 JavaScript、CSS、图片等。Webpack 可以将这些文件打包成一个或多个文件&#xff0c;以便在浏览器中高效加载。它就像…

SOME/IP--协议英文原文讲解6

前言 SOME/IP协议越来越多的用于汽车电子行业中&#xff0c;关于协议详细完全的中文资料却没有&#xff0c;所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块&#xff1a; 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 4.1.4.4 S…

红队视角出发的k8s敏感信息收集——Kubernetes API 扩展与未授权访问

针对 Kubernetes API 扩展与未授权访问 的详细攻击视角分析&#xff0c;聚焦 Custom Resource Definitions (CRD) 和 Aggregated API Servers 的潜在攻击面及利用方法&#xff1a; ​ 攻击链示例 1. 攻击者通过 ServiceAccount Token 访问集群 → 2. 枚举 CRD 发现数据库配…

节目选择器安卓软件编写(针对老年人)

文章目录 需求来源软件界面演示效果源码获取 对爬虫、逆向感兴趣的同学可以查看文章&#xff0c;一对一小班教学&#xff1a;https://blog.csdn.net/weixin_35770067/article/details/142514698 需求来源 由于现在的视频软件过于复杂&#xff0c;某客户想开发一个针对老年人、…

VSCode 接入DeepSeek V3大模型,附使用说明

VSCode 接入DeepSeek V3大模型,附使用说明 由于近期 DeepSeek 使用人数激增,服务器压力较大,官网已 暂停充值入口 ,且接口响应也开始不稳定,建议使用第三方部署的 DeepSeek,如 硅基流动 或者使用其他模型/插件,如 豆包免费AI插件 MarsCode、阿里免费AI插件 TONGYI Lin…

锂电池matlab模型,适用物理对象建模

锂电池matlab模型&#xff0c;适用物理对象建模 资源文件列表 ml_central_ssc_Li_cell/R2010b/LiBatteryElements/C_ext.ssc , 841 ml_central_ssc_Li_cell/R2010b/LiBatteryElements/Em_ext.ssc , 1115 ml_central_ssc_Li_cell/R2010b/LiBatteryElements/R_ext.ssc , 715 ml_…

(萌新入门)如何从起步阶段开始学习STM32 ——2 我应该学习HAL库还是寄存器库?

概念 笔者下面需要介绍的是库寄存器和HAL库两个重要的概念&#xff0c;在各位看完之后&#xff0c;需要决定自己的学习路线到底是学习HAL呢&#xff1f;还是寄存器呢&#xff1f;还是两者都学习呢&#xff1f; 库寄存器 库寄存器就是简单的封装了我们对寄存器的操作&#xf…

Python 调用 DeepSeek API 案例详细教程

本案例为以 Python 为例的调用 DeepSeek API 的小白入门级详细教程 步骤 先注册并登录 DeepSeek 官网&#xff1a;https://www.deepseek.com/ 手机号验证码注册或登录即可 创建 API KEY 注意保存&#xff0c;写代码时必须提供的 打开 Pycharm 创建工程 并安装 OpenAI 库编写代…