最长广播响应_200分_B卷_图/最短路径算法/Dijkstra算法

最长广播响应

题目描述:

  某通信网络中有N个网络结点,用1到N进行标识。
  网络中的结点互联互通,且结点之间的消息传递有时延,相连结点的时延均为一个时间单位。
  现给定网络结点的连接关系 link[i]={u,v},其中u和v表示网络结点。
  当指定一个结点向其他结点进行广播,所有被广播结点收到消息后都会在原路径上回复一条响应消息.
  请计算发送结点至少需要等待几个时间单位才能收到所有被广播结点的响应消息。
备注:
  N的取值范围为[1,100];
  连接关系link的长度不超过3000,且1 <= u,v <= N;
  网络中任意结点间均是可达的;

输入输出描述:

输入描述:

  输入的第一行为两个正整数,分别表示网络结点的个数N,以及时延列表的长度T;
  接下来的T行输入,表示结点间的连接关系列表;
  最后一行的输入为一个正整数,表示指定的广播结点序号

输出描述:

  输出一个整数,表示发送结点接收到所有响应消息至少需要等待的时长。

示例1:

输入:
	5 7
	1 4
	2 1
	2 3
	2 4
	3 4
	3 5
	4 5
	2
输出:
	4
说明:
	结点2到5的最小时延为2,到剩余结点的最小时延均为1,所以至少要等待2*2=4s。

迪杰斯特拉算法(Dijkstra’s algorithm)

  一种用于求解单源最短路径问题的图算法,它可以在带有非负权重的有向图或无向图中找到从一个起始节点到所有其他节点的最短路径。以下是迪杰斯特拉算法的基本步骤:
1、初始化:
  创建一个空的集合 S,用于存储已经找到最短路径的节点。
  创建一个数组 dist,其中 dist[v] 表示从起始节点到节点 v 的当前已知最短距离。初始时,除了起始节点,其他节点的距离都设为无穷大。
  将起始节点的距离 dist[start] 设为 0。
2、选择最近节点:
  从未加入集合 S 的节点中,选择一个节点 u,使得 dist[u] 最小。
  将节点 u 加入集合 S,表示已经找到从起始节点到节点 u 的最短路径。
3、更新距离:
  对于节点 u 的每个邻接节点 v,如果通过节点 u 到达节点 v 的距离比当前已知的距离 dist[v] 更短,更新 dist[v] 为新的最短距离。
4、重复步骤 2 和 3:
  重复步骤 2 和 3,直到集合 S 包含所有节点,即所有节点的最短路径都已找到。
5、得到最短路径:
  一旦算法完成,对于每个节点 v,最短路径的距离即为 dist[v],可以通过反向追踪得到从起始节点到节点 v 的具体路径。
  迪杰斯特拉算法的关键在于每次选择一个最近节点并更新其邻接节点的距离。这样,逐步地扩展集合 S,最终找到从起始节点到所有其他节点的最短路径。
  需要注意的是,迪杰斯特拉算法要求图中的边权重必须为非负值。

解题思路:

题目的意思理解后,就是求解:从 点i 到 点j 之间的最短路径。
可以使用Dijkstra迪杰斯特拉算法来求解最短路径(将每条边权重默认为 1)。

最短路径

代码:

public static void main(String[] args) {
	Scanner scanner = new Scanner(System.in);
	String[] split = scanner.nextLine().split(" ");
	int m = Integer.parseInt(split[0]);
	int n = Integer.parseInt(split[1]);

	// 使用hashMap存储节点的连接关系
	HashMap<Integer, HashSet<Integer>> map = new HashMap<>();
	// 处理邻接表
	for (int i = 0; i < n; i++) {
		int start = scanner.nextInt();
		int end = scanner.nextInt();
		if (!map.containsKey(start)) {
			map.put(start, new HashSet<>());
		}
		if (!map.containsKey(end)) {
			map.put(end, new HashSet<>());
		}
		// 记录下当前节点和邻接节点互为邻接的关系
		map.get(start).add(end);
		map.get(end).add(start);
	}

	// 使用优先级队列来存储起始点
	int head = scanner.nextInt();
	Deque<Integer> queue = new ArrayDeque<>();
	queue.add(head);
	// 判断是否访问过了
	Set<Integer> visited = new HashSet<>();
	// 最短路径数组
	int[] d = new int[m + 1];
	
	while (!queue.isEmpty()) {
		// 每次取出 从起始节点开始到目前为止,离起始原点最近的节点。用该节点去更新其可达的邻接节点的最短路径
		Integer poll = queue.pollFirst();
		for (Integer node : map.get(poll)) {
			// 更新可达节点的最短路径
			if (!visited.contains(node)) {
				visited.add(node);
				d[node] = d[poll] + 1;
				queue.add(node);
			}
		}
	}

	// 最远最短路径
	int res = 0;
	for (int i = 0; i < m + 1; i++) {
		res = Math.max(res, d[i]);
	}
	System.out.println(res * 2);
}

迪杰斯特拉算法(Dijkstra’s algorithm)案例

     1
A ----  B
|  \      |
|    \    |
3       2
|         |
C ---- D
    1

我们要找到从节点 A 到其他节点的最短路径。

步骤 1:初始化

  • 初始节点:A
  • 集合 S:空
  • dist 数组:A: 0, B: ∞, C: ∞, D: ∞

步骤 2:选择最近节点

  • 初始时,A 是起始节点,所以选择 A。

步骤 3:更新距离

  • 更新 A 的邻接节点 B 和 C:
  • B:dist[B] = min(dist[B], dist[A] + weight(A-B)) = min(∞, 0 + 1) = 1
  • C:dist[C] = min(dist[C], dist[A] + weight(A-C)) = min(∞, 0 + 3) = 3
  • 更新完后,dist 数组变为:A: 0, B: 1, C: 3, D: ∞

步骤 2:选择最近节点

  • 从 B、C、D 中选择最小距离的节点,即 B。

步骤 3:更新距离

  • 更新 B 的邻接节点 A、C 和 D:
  • A 和 C:跳过,因为已经找到更短的路径。
  • D:dist[D] = min(dist[D], dist[B] + weight(B-D)) = min(∞, 1 + 2) = 3
  • 更新完后,dist 数组变为:A: 0, B: 1, C: 3, D: 3

步骤 2:选择最近节点

  • 从 C 和 D 中选择最小距离的节点,即 D。

步骤 3:更新距离

  • 更新 D 的邻接节点 A、B 和 C:
  • A 和 B:跳过,因为已经找到更短的路径。
  • C:dist[C] = min(dist[C], dist[D] + weight(D-C)) = min(3, 3 + 1) = 3
  • 更新完后,dist 数组保持不变:A: 0, B: 1, C: 3, D: 3

步骤 2:选择最近节点

  • 只剩下节点 C 了,所以选择 C。

步骤 3:更新距离

  • 更新 C 的邻接节点 A 和 D:
  • A:跳过,因为已经找到更短的路径。
  • D:跳过,因为已经找到更短的路径。
  • 没有更新,dist 数组保持不变:A: 0, B: 1, C: 3, D: 3

步骤 4:重复步骤 2 和 3

  • 所有节点都已经包含在集合 S 中,算法结束。

步骤 5:得到最短路径

  • A 到 A:[A],距离为 0
  • A 到 B:[A, B],距离为 1
  • A 到 C:[A, C],距离为 3
  • A 到 D:[A, B, D] 或 [A, C, D],距离为 3

在这个例子中,迪杰斯特拉算法找到了从节点 A 到其他节点的最短路径及其距离。注意,最终的路径可能有多条,但是它们的距离是相同的。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值