算法编程题-访问所有节点的最短路径

原题描述

访问所有节点的最短路径。原题为在一张图中,有n个节点,编号为从0到n-1,这个图本身是一个无向连通图,要求一条路径,经过所有节点。注意,每一个节点和每一条边都可以被访问多次。值得关注的一点是图中节点数量不超过12。这个应该是解题的一个关键,不超过12意味着可以用状态压缩来保存当前的节点访问状态,即用12个bit,从低到高,分别表示节点0到节点n-1的访问状态,节点对应位为1,则表示该节点已被访问。

广度优先搜索

思路简述

很容易想到的一种做法就是广度优先搜索,求最短路径什么的,如果图各个边的权重是完全相同的,就可以使用广度优先搜索。广度优先搜索,可以使用双端队列来实现。在本题中,搜索的状态为当前访问的节点和历史访问状态(状态压缩)以及当前访问路径的长度。在实现上,需要用一个哈希表记录已经搜索过的状态,避免重复搜索。

代码

func shortestPathLength(graph [][]int) int {
   
   
    n := len(graph)
	deque := list.New()
	visited := make(map[string]struct{
   
   }, 0)
	// 加入以各个点开始的初始状态
	for i := 0; i < n; i++ {
   
   
		deque.PushBack([]int{
   
   i, 1 << i, 0})  // 初始状态
		visited[fmt.Sprintf("%d-%d", i, 1 << i)] = struct{
   
   }{
   
   }
	}
	for deque.Len() != 0 {
   
   
		cur := deque.Remove(deque.Front()).([]int)
		curPos, state, pathLen := cur[0], cur[1], cur[2]
		if state == (1 << n) - 1 {
   
     // 状态压缩,此时相当于每一个点都被访问了
			return pathLen   // bfs, 所以可以直接返回答案
		}
		// 访问当前节点的所有邻居节点
		for _, adj := range graph[curPos] {
   
   
			newState := state | (1 << adj)
			if _, ok := visited[fmt.Sprintf("%d-%d", adj, newState)]; ok {
   
   
				continue
			}
			deque.PushBack([]int{
   
   adj, newState, pathLen + 1})
			visited[fmt.Sprintf("%d-%d", adj, newState)] = struct{
   
   }{
   
   }
		}
	}
	return -1
}

复杂度分析

  • 时间复杂度: O ( n 2 ∗ 2 n ) O(n^2* 2^n) O(n22n),由于有哈希表保证在广度优先搜索中不会重复搜索,而状态数一共是 n ∗ 2 n n * 2 ^n n
Dijkstra算法是一种用于求解图中单个源节点到所有其他节点最短路径的贪心算法。该算法的基本思想是从源节点开始,逐步扩展到其他节点,每次选择距离源节点最近且未被访问过的节点,更新其相邻节点的最短距离,直到所有节点都被访问。 以下是使用Python实现基于Dijkstra算法的图最短路径求解的示例代码: ```python import heapq def dijkstra(graph, start): # 初始化距离字典,用于存储从源节点到每个节点的最短距离 distances = {node: float('inf') for node in graph} 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)) return distances # 示例图的邻接表表示 graph = { 'A': {'B': 1, 'C': 4}, 'B': {'A': 1, 'C': 2, 'D': 5}, 'C': {'A': 4, 'B': 2, 'D': 1}, 'D': {'B': 5, 'C': 1} } start_node = 'A' shortest_distances = dijkstra(graph, start_node) print(f"从节点 {start_node} 到其他节点的最短距离:") for node, distance in shortest_distances.items(): print(f"到节点 {node} 的最短距离: {distance}") ``` ### 代码解释 1. **初始化距离字典**:将所有节点的初始距离设为无穷大,源节点的距离设为0。 2. **优先队列**:使用优先队列(最小堆)来存储待处理的节点及其距离,确保每次取出的节点是距离源节点最近的节点。 3. **遍历节点**:从优先队列中取出距离最小的节点,更新其邻居节点的最短距离,并将更新后的邻居节点加入优先队列。 4. **返回结果**:最终返回从源节点到所有其他节点的最短距离。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值