LeetCode之团灭Dijkstra算法

这篇具有很好参考价值的文章主要介绍了LeetCode之团灭Dijkstra算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

算法背景

算法描述

算法模版

力扣刷题

参考文章


算法背景

地图中的导航功能就是基于迪杰斯特拉算法(Dijkstra)实现的,力扣周赛中经常出现基于这个算法的变种题

算法描述

算法目标:给出一个起始点,我们可以求出到达其他所有点的最短路径

  • 例:假设v​1​​为源点,找从v​1​​到其它节点的最短路径

LeetCode之团灭Dijkstra算法

  • 集合S用来存储已经找到的最短路径
  • v1到自己显然最短,故为初始最短路径

LeetCode之团灭Dijkstra算法

初始表格

第一轮:从v1出发,计算v1到其它节点的距离(无法连接则用“无穷”符号)

LeetCode之团灭Dijkstra算法

计算v1到其它节点的距离,无法连接则用“无穷”符号

  • 全表找最小值,发现v1到v6最短为3
  • S中添加一条最短路径:v1——v6
  • v6列标红不再考虑

LeetCode之团灭Dijkstra算法

v1——v6为新发现的最短路径

第二轮:从v1——v6出发,计算v1通过v6到其它节点的距离

  • 已知v1到v6为3;v6可以到v2,v4,v5;因此,v1通过v6到其它节点的距离为3+n,n为6到各节点的距离

LeetCode之团灭Dijkstra算法

v1——v6到其它现存节点的距离(v6列已删除)

  • 全表中找最小值(v6列已经删除),此时4为最小值,对应路径v1——v6——v5
  • 添加最短路径v1——v6——v5
  • v5列不再考虑

LeetCode之团灭Dijkstra算法

v1——v6——v5为新发现的最短路径

第三轮:从v1——v6——v5出发,计算v1通过v6及v5到其它节点的距离

  • 已知v1——v6——v5长度为4;
  • 发现,v5不能到现存的其它任何一个节点,因此距离全部为“无穷”

LeetCode之团灭Dijkstra算法

v1——v6——v5到其它现存节点的距离(v5,v6列已删除)

  • 全表(v5和v6已经删除)找最小值,5是最小值,对应的路径是v1——v6——v2
  • 添加最短路径v1——v6——v2
  • v2列不再考虑

LeetCode之团灭Dijkstra算法

新最短路径:v1——v6——v2

第四轮:从v1——v6——v2出发,计算v1通过v6及v2到其它节点的距离

LeetCode之团灭Dijkstra算法

v1——v6——v2到其它现存节点的距离(v2,v5,v6已删除)

  • 遍历全表(v2,v5和v6已经删除)发现,9最小,对应的路径为v1——v6——v4
  • 添加最短路径v1——v6——v4
  • v4列不再考虑

LeetCode之团灭Dijkstra算法

新最短路径:v1——v6——v4

第五轮:从v1——v6——v4出发,计算v1通过v6及v4到其它节点的距离

LeetCode之团灭Dijkstra算法

计算v1——v6——v4到其它节点的距离(只剩v3列)

  • 遍历全表发现,12是现存的最小值,对应v1——v6——v2——v3路径最短
  • 添加最短路径v1——v6——v2——v3
  • v3列不再考虑

LeetCode之团灭Dijkstra算法

添加最后一条最短路径:v1——v6——v2——v3

  • 由于全部列已经删除,因此结束遍历

  • 最终的表格

LeetCode之团灭Dijkstra算法

最终表格

  • 每列的标红值,则为v1到该节点的最短距离;从S列中找结尾为该列的路径。
  • 例如,v2列标红值为5,说明v1到v2的最短路径为5
  • S中结尾为v2,对应的路径为v1——v6——v2

结果汇总

  • v1到各节点的路径及其最短距离
    • v6v1——v6 = 3
    • v5v1——v6——v5 = 4
    • v4v1——v6——v4 = 9
    • v3v1——v6——v2——v3 = 12
    • v2v1——v6——v2 = 5

算法模版

public class Dijkstra {
	
	static class Node {
		int x; // 节点编号
		int lenth;// 用于记录起点到该节点的最短路径的临时变量

		public Node(int x, int lenth) {
			this.x = x;
			this.lenth = lenth;
		}
	}

	public static void main(String[] args) {

		int[][] map = new int[6][6];// 记录权值,顺便记录链接情况,可以考虑附加邻接表
		initmap(map);// 初始化
		boolean visited[] = new boolean[6];// 判断是否已经确定
		int len[] = new int[6];// 用于记录起点到对应节点的最终的最短路径长度
		for (int i = 0; i < 6; i++) {
			len[i] = Integer.MAX_VALUE;
		}
 
		
		PriorityQueue<Node> q1 = new PriorityQueue<>((a, b) -> {
			return a.lenth - b.lenth;
		});
		
		len[0] = 0;// 从0这个点开始
		q1.add(new Node(0, 0));


		while (!q1.isEmpty()) {
			Node t1 = q1.poll();
			int index = t1.x;// 节点编号
			int length = t1.lenth;// 节点当前点距离
			visited[index] = true;// 抛出的点确定
			for (int i = 0; i < map[index].length; i++) {
				if (map[index][i] > 0 && !visited[i]) {
					Node node = new Node(i, length + map[index][i]);
					if (len[i] > node.lenth)// 需要更新节点的时候更新节点并加入队列
					{
						len[i] = node.lenth;
						q1.add(node);
					}
				}
			}
		}
		for (int i = 0; i < 6; i++) {
			System.out.println(len[i]);
		}
	}

	static Comparator<Node> com = new Comparator<Node>() {

		public int compare(Node o1, Node o2) {
			return o1.lenth - o2.lenth;
		}
	};

	private static void initmap(int[][] map) {
		map[0][1] = 2;
		map[0][2] = 3;
		map[0][3] = 6;
		map[1][0] = 2;
		map[1][4] = 4;
		map[1][5] = 6;
		map[2][0] = 3;
		map[2][3] = 2;
		map[3][0] = 6;
		map[3][2] = 2;
		map[3][4] = 1;
		map[3][5] = 3;
		map[4][1] = 4;
		map[4][3] = 1;
		map[5][1] = 6;
		map[5][3] = 3;
	}
}

力扣刷题

public class LeetCode1976到达目的地的方案数 {

	public int countPaths(int n, int[][] roads) {

		boolean visited[] = new boolean[n];// 判断是否已经确定
		int len[] = new int[n]; // 记录从起点到各节点的最短路径长度
		int[] cnt = new int[n]; // 记录从起点到各节点的最短路径数量

		for (int i = 0; i < n; i++) {
			len[i] = Integer.MAX_VALUE;
		}

		int[][] map = initmap(roads, n);

		PriorityQueue<Node> q1 = new PriorityQueue<>((a, b) -> {
			return a.lenth - b.lenth;
		});

		len[0] = 0;// 从0这个点开始
		q1.add(new Node(0, 0));
		cnt[0] = 1; // start -> start的最短路径只有一条

		while (!q1.isEmpty()) {
			Node t1 = q1.poll();
			int index = t1.x;// 节点编号
			int length = t1.lenth;// 节点当前点距离
			visited[index] = true;// 抛出的点确定
			for (int i = 0; i < map[index].length; i++) {
				if (map[index][i] > 0 && !visited[i]) {
					Node node = new Node(i, length + map[index][i]);
					if (len[i] > node.lenth)// 需要更新节点的时候更新节点并加入队列
					{
						cnt[i] = cnt[index];
						len[i] = node.lenth;
						q1.add(node);
					} else if (len[i] == node.lenth) {
						// 如果当前最短路径长度相等,则累加路径数量
						// 如果发现有另一个路径,它的长度和当前的最短路径长度相等,那么这条路径也是最短路径之一。
						// 因此,我们需要将这条路径的数量加到当前节点的最短路径数量 cnt[i] 中
						cnt[i] = (cnt[i] + cnt[index]) % 1000000007;
					}
				}
			}
		}
		return cnt[n - 1];

	}

	private int[][] initmap(int[][] roads, int n) {

		int[][] map = new int[n][n];

		for (int i = 0; i < roads.length; i++) {
			map[roads[i][0]][roads[i][1]] = roads[i][2];
			map[roads[i][1]][roads[i][0]] = roads[i][2];
		}

		return map;

	}

	class Node {
		int x; // 节点编号
		int lenth;// 用于记录起点到该节点的最短路径的临时变量

		public Node(int x, int lenth) {
			this.x = x;
			this.lenth = lenth;
		}
	}

	public static void main(String[] args) {

		int[][] roads = { { 1, 0, 10 } };
		new LeetCode1976到达目的地的方案数().countPaths(2, roads);
	}
}
public class LeetCode2642设计可以求最短路径的图类 {

	class Graph {

		int[][] map = null;
		boolean visited[] = null;
		int len[] = null;

		public Graph(int n, int[][] edges) {

			map = new int[n][n];
			visited = new boolean[n];// 判断是否已经确定
			len = new int[n]; // 记录从起点到各节点的最短路径长度

			for (int i = 0; i < edges.length; i++) {
				map[edges[i][0]][edges[i][1]] = edges[i][2];
			}
			for (int i = 0; i < n; i++) {
				len[i] = Integer.MAX_VALUE;
			}
		}

		public void addEdge(int[] edge) {

			dijkstra(edge[0]);
			map[edge[0]][edge[1]] = edge[2];

		}

		public int shortestPath(int node1, int node2) {
			// 先检查 node1 到 node2 之间是否有直接的边
	        if (map[node1][node2] > 0) {
	        	return map[node1][node2]; 
	        }
 
			return len[node2];

		}
		
	    public void dijkstra(int source) {
	    	
	        Arrays.fill(visited, false);
	        Arrays.fill(len, Integer.MAX_VALUE);
	    	
			PriorityQueue<Node> q1 = new PriorityQueue<>((a, b) -> {
				return a.lenth - b.lenth;
			});

			len[source] = -1;// 从node1这个点开始
			q1.add(new Node(source, 0));

			while (!q1.isEmpty()) {

				Node t1 = q1.poll();
				int index = t1.x;// 节点编号
				int length = t1.lenth;// 节点当前点距离
				visited[index] = true;// 抛出的点确定
				for (int i = 0; i < map[index].length; i++) {
					if (map[index][i] > 0 && !visited[i]) {
						Node node = new Node(i, length + map[index][i]);
						if (len[i] > node.lenth)// 需要更新节点的时候更新节点并加入队列
						{
							len[i] = node.lenth;
							q1.add(node);
						}
					}
				}
			}
	    	
	    }

		class Node {
			int x; // 节点编号
			int lenth;// 用于记录起点到该节点的最短路径的临时变量

			public Node(int x, int lenth) {
				this.x = x;
				this.lenth = lenth;
			}
		}
	}

}
public class LeetCode2662前往目标的最小代价{

	public int minimumCost(int[] start, int[] target, int[][] specialRoads) {
		// 创建一个优先级队列,用于存储每个位置和到达该位置的代价,按代价从小到大排序
		PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> {
			return a[2] - b[2];
		});
		// 初始化结果为从起点到终点的直线距离
		int res = dist(start, target);
		// 将起点加入优先级队列
		pq.offer(new int[] { start[0], start[1], 0 });
		// 创建一个 HashMap 用于存储已访问过的位置和到达该位置的最小代价
		Map<String, Integer> vis = new HashMap<>();
		vis.put(getKey(start), 0);

		while (!pq.isEmpty()) {
			// 每次从队列中取出代价最小的位置
			int[] p = pq.poll();
			// 遍历所有特殊路径
			for (int[] sp : specialRoads) {
				int[] p1 = new int[] { sp[0], sp[1] };
				int[] p2 = new int[] { sp[2], sp[3] };
				// 计算从当前位置到特殊路径起点的代价,再加上特殊路径的代价
				int d = p[2] + dist(p, p1) + sp[4];
				String key = getKey(p2);
				// 获取之前到达特殊路径终点的最小代价,如果没有则为从起点到终点的直线距离
				int x = vis.getOrDefault(key, dist(start, p2));
				// 如果新的代价小于之前的最小代价,更新最小代价
				if (d < x) {
					vis.put(key, d);
					pq.offer(new int[] { p2[0], p2[1], d });
					// 更新结果,当前位置到特殊路径终点的代价加上从特殊路径终点到目标位置的代价
					res = Math.min(res, d + dist(p2, target));
				}
			}
		}
		return res;
	}

	// 计算两点之间的代价
	private int dist(int[] p1, int[] p2) {
		return Math.abs(p1[0] - p2[0]) + Math.abs(p1[1] - p2[1]);
	}

	// 将位置转换为字符串,用于在 HashMap 中作为键
	private String getKey(int[] p) {
		return p[0] + "_" + p[1];
	}
}

参考文章

【看完必懂】Dijkstra算法(附案例详解) - 知乎

https://www.cnblogs.com/bigsai/p/11537975.html文章来源地址https://www.toymoban.com/news/detail-476625.html

到了这里,关于LeetCode之团灭Dijkstra算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 简单描述下微信小程序的目录结构

    简单描述下微信小程序的目录结构

    微信小程序的目录结构通常包括以下主要部分: 这是一个典型的微信小程序的目录结构,具体项目可能会有一些变化,但通常都包含类似的核心文件和文件夹。小程序开发者需要按照这个结构组织项目代码和资源 app.js :小程序的主入口文件,用于定义小程序的全局配置,包

    2024年02月07日
    浏览(12)
  • LeetCode 双周赛 101,DP/中心位贪心/裴蜀定理/Dijkstra/最小环

    本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问。 大家好,我是小彭。 这周比较忙,上周末的双周赛题解现在才更新,虽迟但到哈。上周末这场是 LeetCode 第 101 场双周赛,整体有点难度,第 3 题似乎比第 4 题还难一些。 2605. 从两个数字数组里生成最

    2023年04月09日
    浏览(10)
  • 【算法】单源最短路径算法——Dijkstra算法

    【算法】单源最短路径算法——Dijkstra算法

    迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。这是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用 贪心算法 的策略, 每次遍历到始点距离最

    2024年02月05日
    浏览(11)
  • 图算法——求最短路径(Dijkstra算法)

    图算法——求最短路径(Dijkstra算法)

            目录 一、什么是最短路径 二、迪杰斯特拉(Dijkstra)算法  三、应用Dijkstra算法 (1) Dijkstra算法函数分析         求图的最短路径在实际生活中有许多应用,比如说在你在一个景区的某个景点,参观完后,要怎么走最少的路程到你想参观的下个景点,这就利用到

    2023年04月15日
    浏览(8)
  • 最短路径(Dijkstra算法)

    最短路径(Dijkstra算法)

    (1)最短路径: 非网图:两顶点之间经历边数最小的路径 网图:两顶点之间经历的 边上权值之和 最短的路 1.思路 设置一个集合S存放已经找到最短路径的顶点,并设置一个源点,dist[]数组中存放源点距离每个顶点的最短距离,path[]数组中存放的是最短路径,基本过程可以如

    2024年02月09日
    浏览(8)
  • Dijkstra(迪杰斯特拉)算法

    Dijkstra(迪杰斯特拉)算法

    Dijkstra(迪杰斯特拉)算法的思想是广度优先搜索(BFS) 贪心策略。 是从一个顶点到其余各顶点的最短路径算法,节点边是不各自不同的权重,但都必须是正数 如果是负数,则需要 Bellman-Ford 算法 如果想求任意两点之间的距离,就需要用 Floyd 算法 求节点0 - 4 的最短路径 每次从

    2024年04月12日
    浏览(12)
  • Dijkstra算法

    Dijkstra算法

    Dijkstra是一位荷兰的计算机科学家和数学家,他被认为是计算机科学领域的先驱之一。他于1930年5月11日出生于荷兰的鹿特丹,于2002年8月6日去世于荷兰的努南。Dijkstra最为人们所熟知的是他在算法问题解决和编程语言方面的贡献。 Dijkstra最重要的贡献之一就是他开发了最短路

    2024年02月06日
    浏览(6)
  • Dijkstra算法实现(java)

    Dijkstra算法实现(java)

      Dijkstra(迪杰斯特拉)算法是求解单源最短路径的经典算法,其原理也是基于贪心策略的。   Dijkstra算法设置一个集合 S S S 记录已求得的最短路径的顶点,初始时把源点 v 0 v_{0} v 0 ​ 放入 S S S ,集合 S S S 每并入一个新顶点 v i v_{i} v i ​ ,都要修改源点 v 0 v_{0} v 0 ​

    2023年04月08日
    浏览(7)
  • 最短路径(Dijkstra)算法

    目录 一、Dijkstra算法 二、核心思路 三、步骤 四、代码 迪杰斯特拉(Dijkstra)算法是由荷兰计算机科学家狄克斯特拉于1959年提出的。是寻找从一个顶点到其余各顶点的最短路径算法,可用来 解决最短路径问题 。

    2024年02月07日
    浏览(9)
  • Dijkstra算法详解

    Dijkstra算法详解

    迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又 叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是 有权图中最 短路径问题 。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍 历到始点距离最近

    2024年03月20日
    浏览(7)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包