算法学习笔记(7.7)-贪心算法(Dijkstra算法-最短路径问题)

news2024/12/24 6:05:35

目录

1.最短路径问题

 2.Dijkstra算法介绍

 3.Dijkstra算法演示

4.Dijkstra算法的代码示例


1.最短路径问题

图论中的一个经典问题,通常是指在一个加权图中找到从一个起始顶点到目标顶点的最短路径。

  1. 单源最短路径问题:给定一个加权图和一个起始顶点,要找到从该起始顶点到图中所有其他顶点的最短路径。

    • Dijkstra算法:适用于没有负权边的图,能够找到单源最短路径。

    • Bellman-Ford算法:适用于存在负权边的图,能够找到单源最短路径。

  2. 全源最短路径问题:给定一个加权图,要找到图中任意两个顶点之间的最短路径。

    • Floyd-Warshall算法:适用于有向图或无向图,能够找到所有顶点之间的最短路径。
  3. 最短路径问题的应用

    • 在网络路由中,确定数据包的最佳路径。

    • 在地图应用程序中,找到两个地点之间的最短驾驶路径。

    • 在交通规划中,优化公交线路或货运路径。

    • 在电路设计中,找到电路中信号传输的最短路径。

  4. 解决最短路径问题的算法

    • Dijkstra算法:适用于非负权重的图,能够找到单源最短路径。

    • Bellman-Ford算法:适用于存在负权重的图,能够找到单源最短路径。

    • A*算法:一种启发式搜索算法,用于寻找从起点到目标点的最短路径。

    • Bellman-Ford算法:适用于有向图或无向图,能够找到所有顶点之间的最短路径。

 2.Dijkstra算法介绍

1.Dijkstra算法特点:

迪科斯彻算法使用了广度优先搜索解决赋权有向图或者无向图的单源最短路径问题,算法最终得到一个最短路径树。该算法常用于路由算法或者作为其他图算法的一个子模块。

2.Dijkstra算法的步骤:

2.1 初始化:创建一个空的集合用于存储已经找到最短路径的顶点,以及一个数组用于存储从起始顶点到每个顶点的最短距离。将起始顶点的最短距离设置为0,其他顶点的最短距离设置为无穷大。

2.2 选取起始顶点:将起始顶点加入集合,更新起始顶点到相邻顶点的最短距离。

2.3 重复步骤:重复以下步骤,直到所有顶点都被加入集合为止:
   2.3.1 从未加入集合的顶点中选取与起始顶点距离最短的顶点加入集合。
   2.3.2 更新该顶点到相邻顶点的最短距离,如果经过该顶点到相邻顶点的距禒小于已知的最短距离,则更新最短距离。

2.4 最终结果:当所有顶点都被加入集合后,最短路径就被找到了。

3. Dijkstra算法的特点和适用性:

3.1 Dijkstra算法适用于带权重的有向图或无向图。
3.2 该算法保证找到的路径是最短的,但前提是图中不能有负权重的边
3.3 时间复杂度取决于具体实现,通常在稠密图上的时间复杂度为O(V^2),在稀疏图上的时间复杂度为O(E * log V)。
3.4 Dijkstra算法常用于路由算法、网络分析、地图应用等领域。

4. Dijkstra核心算法思想:

迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止

 3.Dijkstra算法演示

1.用一个 dist 数组保存源点到其余各个节点的距离,dist[i] 表示源点到节点 i 的距离。初始时,dist 数组的各个元素为无穷大。用一个状态数组 state 记录是否找到了源点到该节点的最短距离,state[i] 如果为真,则表示找到了源点到节点 i 的最短距离,state[i] 如果为假,则表示源点到节点 i 的最短距离还没有找到。初始时,state 各个元素为假。

2.源点到源点的距离为 0。即dist[1] = 0。

3.遍历 dist 数组,找到一个节点,这个节点是:没有确定最短路径的节点中距离源点最近的点。假设该节点编号为 i。此时就找到了源点到该节点的最短距离,state[i] 置为 1。

4.遍历 i 所有可以到达的节点 j,如果 dist[j] 大于 dist[i] 加上 i -> j 的距离,即 dist[j] > dist[i] + w[i][j](w[i][j] 为 i -> j 的距离) ,则更新 dist[j] = dist[i] + w[i][j]。

5.重复 3 4 步骤,直到所有节点的状态都被置为 1。


6.此时 dist 数组中,就保存了源点到其余各个节点的最短距离。

4.Dijkstra算法的代码示例

//c++代码实现
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

const int N = 510, M = 100010, INF = 0x3f3f3f3f;

int h[N], e[M], ne[M], w[M], idx;
//h数组用来储存每个边链表的头部
//e数组用来存储每条边指向的节点编号
//w用来存储每条边的权重
//ne数组用来实现邻接表中的链表结构 
int dist[N]; //state 记录是否找到了源节点到该节点的最短距离
bool state[N]; //dist 数组保存源点到其余各个节点的距离
int n, m; //图的节点个数和边数
int adjMatrix[N][N];  // 邻接矩阵

void add(int a, int b, int c) 
{
	e[idx] = b ; //将当前边的目标节点b存储在,e[idx]中 
	w[idx] = c ; //将该条边的权重存储在,w[idx]中 
	ne[idx] = h[a] ; //更新ha将之前节点a的第一条边的索引存储在ne数组,使其一直处于更新状态指向最新的一条边 
	h[a] = idx++ ;	
}

// 打印邻接表
void printAdjList() {
    for (int i = 1; i <= n; ++i) {
        cout << "Vertex " << i << ":";
        for (int j = h[i]; j != -1; j = ne[j]) {
            cout << "-> (" << e[j] << ", " << w[j] << ")";
        }
        cout << endl;
    }
}

// 创建并打印邻接矩阵
void printAdjMatrix() {
    // 初始化邻接矩阵
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            if (i == j) adjMatrix[i][j] = 0;
            else adjMatrix[i][j] = INF;
        }
    }
    
    // 填充邻接矩阵
    for (int i = 1; i <= n; ++i) {
        for (int j = h[i]; j != -1; j = ne[j]) {
            int to = e[j];
            adjMatrix[i][to] = min(adjMatrix[i][to], w[j]);  // 如果有重边,保留权重最小的一条
        }
    }
    
    // 打印邻接矩阵
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            if (adjMatrix[i][j] == INF) cout << "INF ";
            else cout << adjMatrix[i][j] << " ";
        }
        cout << endl;
    }
}

void Dijkstra()
{
	memset(dist, 0x3f, sizeof(dist)) ; //dist 初始化数组中的元素为最大值
	dist[1] = 0 ;
	for (int i = 0 ; i < n ; i++)
	{
		int t = -1 ;
		for (int j = 1 ; j <= n ; j++)
		{
			//遍历 dist 数组,找到没有确定最短路径的节点 
			if (!state[j] && (t == -1 || dist[j] < dist[t]))
			{
				t = j ;	
			}
		}
		state[t] = 1 ; //将该位置置为访问
			
		for (int j = h[t]; j != -1 ; j = ne[j]) //遍历 t 所有可以到达的节点i 
		{
			int i = e[j] ;
			dist[i] = min(dist[i], dist[t] + w[j]) ; //更新dist[j] 
		}	
			
	} 
}

int main()
{
	memset(h, -1, sizeof(h)) ;
	
	cin >> n >> m ;
	while (m--)
	{
		int a, b, w ;
		cin >> a >> b >> w ;
		add(a, b, w) ;
	}
	Dijkstra() ;
	if (dist[n] != 0x3f3f3f3f)
	{
		cout << dist[n] ;
	}
	else
	{
		cout << "-1" ;
	}
	// 打印邻接表
    printAdjList();
    // 创建并打印邻接矩阵
    printAdjMatrix();
	return 0 ;
}

#python代码示例

# 简单的Dijkstra算法
import heapq

def dijkstra(graph, start) :
    # 初始化距离字典,将所有节点的距离设置为无穷大
    distances = {node : float('inf') for node in graph}
    # 源节点到自身的距离设置为0
    distances[start] = 0
    # 使用优先队列来进行优化,队列中的元素(距离,节点)
    priority_queue = [(0,start)]

    while priority_queue :
        # 弹出队列中最小距离的节点
        current_distance, current_node = heapq.heappop(priority_queue)
        # 如果弹出的节点距离大于当前记录的距离,则忽略(已找到更短路径)
        if current_distance > distances[current_node] :
            continue
        # 遍历相邻的节点,更新距离
        for neighbor, weight in graph[current_node].items() :
            distance = current_distance + weight
            # 如果通过当前节点到达相邻节点的距离更短,则更新距离字典和最小堆
            if distance < distances[neighbor] :
                distances[neighbor] = distance
                heapq.heappush(priority_queue,(distance,neighbor))
                print(f"更新节点: {neighbor} 的最短路径为: {distance}")
    return distances

graph = {
'A': {'B': 1, 'C': 3},
'B': {'A': 1, 'C': 1, 'D': 4},
'C': {'A': 3, 'B': 2, 'D': 1},
'D': {'B': 4, 'C': 1}
}
start = 'A'
# print(dijkstra(graph, start))  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}

shortest_paths = dijkstra(graph, start)
print("\n从节点 {} 到图中其他节点的最短路径:".format(start))
for node, distance in shortest_paths.items():
    print(f"到节点 {node} 的最短距离是: {distance}")

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

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

相关文章

http协议,tomcat的作用

HTTP 概念:Hyper Text Transfer Protocol&#xff0c;超文本传输协议&#xff0c;规定了浏览器和服务器之间数据传输的规则。 特点: 1.基于TCP协议:面向连接&#xff0c;安全 2. 基于请求-响应模型的:一次请求对应一次响应 3HTTP协议是无状态的协议:对于事务处理没有记忆能…

react学习-高阶组件

1.简介 react高阶组件是一个函数&#xff0c;接收一个组件作为参数&#xff0c;返回一个新的组件&#xff0c;可以用来进行组件封装&#xff0c;将一些公共逻辑提取到高阶组件内部。 2.基本实现 以下案例为利用高阶组件来增强props import React, { Component } from "re…

10.dockerfile自动构建镜像

dockerfile自动构建镜像 类似ansible剧本&#xff0c;大小几kb 手动做镜像&#xff1a;大小几百M 首先创建一个dockerfile的路径&#xff0c;便于在路径下存在多个路径每个路径下都是dockerfile命名的脚本 注释&#xff1a;文件必须为&#xff1a;dockerfile或者Dockerfile …

解决linux系统求前N月月份的bug

日常工作中&#xff0c;需要获取某个日期&#xff08;20240531&#xff09;的前N个月&#xff0c;通常会写命令 date -d "20240531 last-month" %Y%m 我期望得到202404 但是很意外&#xff1a; 经过几轮测试&#xff0c;发现只要月内天数超过30天&#xff0c;即所有…

基于Zero-shot实现LLM信息抽取

基于Zero-shot方式实现LLM信息抽取 在当今这个信息爆炸的时代&#xff0c;从海量的文本数据中高效地抽取关键信息显得尤为重要。随着自然语言处理&#xff08;NLP&#xff09;技术的不断进步&#xff0c;信息抽取任务也迎来了新的突破。近年来&#xff0c;基于Zero-shot&#x…

代码随想录——修建二叉搜素树(Leetcode669)

题目链接 递归 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

【算法每日一练】新月轩就餐

思路&#xff1a; 其实很容易想到是双指针或者双端队列。 我们设置一个type表示当前区间已经有了多少种厨师&#xff0c;同时还需要记录区间中每个元素出现的次数&#xff0c;然后比较棘手的是移动问题了&#xff0c;什么时候移动呢&#xff1f; 我们可以发现当区间当队头元…

AI数据分析:用deepseek根据Excel数据绘制分裂饼形图

工作任务&#xff1a;要绘制下面表格中月活用户占比的分裂饼形图 在deepseek中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个Python脚本编写的任务&#xff0c;具体步骤如下&#xff1a; 读取Excel文件"F:\AI自媒体内容\AI行业数据分析\poetop5…

Polar Web 【简单】- 被黑掉的站

Polar Web 【简单】- 被黑掉的站 Contents Polar Web 【简单】- 被黑掉的站思路EXP运行&总结 思路 如题目所述&#xff0c;这是一个被黑掉的站点&#xff0c;由此不禁要了解该黑客发现了哪些可以入手的路径&#xff0c;或是留下了什么样的文件供持续访问。 目录扫描该站点发…

软件测试--Linux快速入门

文章目录 软件测试-需要掌握的Linux指令Linux命令操作技巧Linx命令的基本组成常用命令 软件测试-需要掌握的Linux指令 Linux命令操作技巧 使用Tab键自动补全上下键进行翻找之前输入的命令命令执行后无法停止使用CtrC,结束屏幕输出 Linx命令的基本组成 命令 [-选项] [参数] …

Attention注意力机制:理论基础、核心架构、应用领域及最新研究动态

Attention机制源于对序列建模中长期依赖关系的有效捕获需求&#xff0c;其理论基础在于让模型动态分配权重以聚焦于输入序列中与当前任务相关的关键部分。核心架构包括Query-Key-Value三元组计算、Softmax归一化的注意力得分、加权求和生成上下文向量&#xff0c;以及扩展至多头…

Unity3d简单对话系统的实现——使用Dialogue editor完成对话系统

目录 前言 使用方法 1.下载dialogue editor 2.新建空物体 3.对对话内容进行编辑 4.对话画布建立 5.触发对话框代码 结束语 前言 今天是坚持写博客的第21天&#xff0c;很高兴自己可以坚持&#xff0c;也希望能与大家一起进步。我们今天来看unity3d当中的一个可以轻松实…

Python易错点总结

目录 多分支选择结构 嵌套选择 用match模式识别 match与if的对比 案例&#xff1a;闰年判断 三角形的判断 用whlie循环 高斯求和 死循环 用for循环 ​编辑continue​编辑 whlie与else结合 pass 序列 列表&#xff08;有序&#xff09; 元组&#xff08;有序&…

高防CDN是如何应对DDoS和CC攻击的

高防CDN&#xff08;内容分发网络&#xff09;主要通过分布式的网络架构来帮助网站抵御DDoS&#xff08;分布式拒绝服务&#xff09;和CC&#xff08;挑战碰撞&#xff09;攻击。 下面是高防CDN如何应对这些攻击的详细描述&#xff1a; 1. DDoS攻击防护 DDoS攻击通过大量的恶…

数智融通 创新发展|亚信科技携AntDB、Data OS与隐私计算产品,赋能企业高质量发展

5月21日&#xff0c;亚信科技在云端举办了一场别开生面的研讨会——“数智融通 创新发展”&#xff0c;聚焦企业数智化升级的前沿话题。资深产品经理和技术架构师们面对面深入交流&#xff0c;分享创新成果与实战案例&#xff0c;共同探索企业数智化转型的新路径。 图1&#xf…

2024华为数通HCIP-datacom最新题库(变题更新③)

请注意&#xff0c;华为HCIP-Datacom考试831已变题 请注意&#xff0c;华为HCIP-Datacom考试831已变题 请注意&#xff0c;华为HCIP-Datacom考试831已变题 近期打算考HCIP的朋友注意了&#xff0c;如果你准备去考试&#xff0c;还是用的之前的题库&#xff0c;切记暂缓。 1、…

Erlang

官网地址&#xff1a; Index - Erlang/OTP windows环境变量配置 创建新系统变量 ERLANG_HOME 在path加入上述配置

Golang使用讯飞星火AI接口

一、API申请 https://www.bilibili.com/video/BV1Yw411m7Rs/?spm_id_from333.337.search-card.all.click&vd_source707ec8983cc32e6e065d5496a7f79ee6 注册申请&#xff0c;需要在此页面获取appid、apisecret、apikey https://www.xfyun.cn/ https://console.xfyun.cn/ser…

正确挑选百兆超薄款工业级网络/脉冲变压器(网络隔离滤波器)

Hqst华强盛&#xff08;石门盈盛电子&#xff09;导读&#xff1a;工业级百兆超薄款网络变压器的生产要特殊的超薄磁芯配正确线径的铜线&#xff0c;使用符合相应防潮标准的凝固胶水。 一 ̖ 首先来看下商业级的超薄款的百兆网络变压器&#xff1a; 商业级&#xff08;消费级&…

先求生存,再谋发展:俞敏洪的创业哲学与产品创新之路

引言&#xff1a; 在创业的道路上&#xff0c;每一个创业者都面临着无数的挑战和选择。俞敏洪&#xff0c;新东方教育科技集团的创始人&#xff0c;以其独特的创业哲学和坚韧不拔的精神&#xff0c;带领新东方从一个小小的培训机构成长为全球知名的教育品牌。他的成功经验告诉…