文心一言 VS 讯飞星火 VS chatgpt (366)-- 算法导论24.3 8题

news2024/12/27 15:42:12

八、给定带权重的有向图 G = ( V , E ) G=(V,E) G=(VE) ,其权重函数为 w : E → ( 0 , 1 , 2. … , W ) w:E→(0,1,2.…,W) w:E(012.W) ,这里 W W W为某个非负整数。请修改 Diikstra 算法来计算从给定源结点 s s s 到所有结点之间的最短路径。该算法时间应为 O ( W V + E ) O(WV+E) O(WV+E) 。如果要写代码,请用go语言。

文心一言:

Dijkstra 算法通常用于计算带非负权重的无向图或有向图中从单一源点到所有其他点的最短路径。标准的 Dijkstra 算法的时间复杂度是 O ( ( V + E ) log ⁡ V ) O((V + E) \log V) O((V+E)logV),因为它通常使用优先队列(如最小堆)来管理当前最短路径的节点。

然而,在你的特定情况下,权重函数 w : E → { 0 , 1 , 2 , … , W } w:E \rightarrow \{0, 1, 2, \ldots, W\} w:E{0,1,2,,W} 限制了边的权重只能是从 0 到 W W W 的整数。我们可以利用这个特性,用一个数组来代替优先队列,从而实现 O ( W V + E ) O(WV + E) O(WV+E) 的时间复杂度。

下面是使用 Go 语言实现的修改后的 Dijkstra 算法:

package main

import (
	"fmt"
	"math"
)

const INF = math.MaxInt32

// Edge represents a directed edge in the graph
type Edge struct {
	to     int
	weight int
}

// Graph represents a directed graph with weighted edges
type Graph struct {
	vertices int
	edges    map[int][]Edge
}

// NewGraph creates a new graph with a given number of vertices
func NewGraph(vertices int) *Graph {
	return &Graph{
		vertices: vertices,
		edges:    make(map[int][]Edge),
	}
}

// AddEdge adds a directed edge to the graph
func (g *Graph) AddEdge(from, to, weight int) {
	g.edges[from] = append(g.edges[from], Edge{to, weight})
}

// Dijkstra calculates the shortest paths from the source node to all other nodes
func (g *Graph) Dijkstra(source int) []int {
	dist := make([]int, g.vertices)
	for i := range dist {
		dist[i] = INF
	}
	dist[source] = 0

	// Use an array to simulate a priority queue for weights 0 to W
	bucket := make([][]int, g.vertices*g.vertices+1) // Assume W < V^2 for simplicity
	for i := range bucket {
		bucket[i] = make([]int, 0)
	}

	// Initialize the bucket with the source node having distance 0
	bucket[0] = append(bucket[0], source)

	for len(bucket[0]) > 0 {
		u := bucket[0][0]
		bucket[0] = bucket[0][1:]

		for _, edge := range g.edges[u] {
			v := edge.to
			alt := dist[u] + edge.weight
			if alt < dist[v] {
				dist[v] = alt
				// Add v to the bucket for its new distance
				bucket[alt] = append(bucket[alt], v)
			}
		}

		// Move all nodes from bucket[0] to the end of the processing queue
		// to ensure they are not revisited before nodes with larger distances
		for i := 1; i < len(bucket); i++ {
			if len(bucket[i]) > 0 {
				bucket[0] = append(bucket[0], bucket[i]...)
				bucket[i] = bucket[i][:0]
			}
		}
	}

	return dist
}

func main() {
	g := NewGraph(5)
	g.AddEdge(0, 1, 1)
	g.AddEdge(0, 4, 5)
	g.AddEdge(1, 2, 2)
	g.AddEdge(1, 4, 2)
	g.AddEdge(2, 3, 4)
	g.AddEdge(3, 2, 6)
	g.AddEdge(4, 1, 3)
	g.AddEdge(4, 2, 9)
	g.AddEdge(4, 3, 2)

	source := 0
	distances := g.Dijkstra(source)

	fmt.Printf("Shortest distances from node %d to all other nodes:\n", source)
	for i, dist := range distances {
		if dist == INF {
			fmt.Printf("Node %d: unreachable\n", i)
		} else {
			fmt.Printf("Node %d: %d\n", i, dist)
		}
	}
}

解释

  1. 数据结构

    • 使用一个 Graph 结构体来表示图,其中 edges 是一个从节点到其邻居节点的映射。
    • Dijkstra 方法使用了一个 dist 数组来存储从源节点到每个节点的最短距离。
  2. 桶(Bucket)模拟优先队列

    • 使用一个二维切片 bucket 来模拟优先队列,其中 bucket[i] 存储了所有距离为 i 的节点。
    • 初始化时,将源节点添加到 bucket[0] 中。
  3. 算法逻辑

    • 不断从 bucket[0] 中取出节点 u,并更新其邻居节点 v 的最短路径。
    • 如果更新后的距离 alt 更小,则将 v 添加到对应的新距离 alt 的桶中。
    • 为了避免重复处理节点,将当前桶 bucket[0] 中的节点移到其他桶的末尾,确保不会重复处理。
  4. 时间复杂度

    • 由于边的权重范围是 0 0 0 W W W,且 W W W 通常远小于 V 2 V^2 V2,因此使用桶模拟优先队列的复杂度是 O ( W V + E ) O(WV + E) O(WV+E)

希望这段代码和解释能帮助你理解如何修改 Dijkstra 算法以适应特定权重范围的需求。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

讯飞星火:

首先,我们需要理解 Dijkstra 算法的基本思想。Dijkstra 算法是一种用于在带权有向图中查找从源节点到所有其他节点的最短路径的算法。它使用了贪心策略,每次选择距离源节点最近的未访问节点,并更新其相邻节点的距离。

为了实现这个算法,我们需要一个优先队列来存储未访问的节点,并根据它们的距离进行排序。我们还需要一个数组来存储每个节点的最短距离。此外,我们需要一个布尔数组来标记已访问的节点。

以下是使用 Go 语言实现的 Dijkstra 算法:

package main

import (
	"fmt"
	"container/heap"
)

type Edge struct {
	to   int
	cost int
}

type Node struct {
	id    int
	dist  int
	edges []Edge
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].dist < pq[j].dist
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
	node := x.(*Node)
	*pq = append(*pq, node)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

func dijkstra(graph []Node, start int) []int {
	dist := make([]int, len(graph))
	for i := range dist {
		dist[i] = -1 // 初始化为无穷大
	}
	dist[start] = 0

	visited := make([]bool, len(graph))
	pq := &PriorityQueue{}
	heap.Init(pq)
	heap.Push(pq, &Node{id: start, dist: 0})

	for pq.Len() > 0 {
		u := heap.Pop(pq).(*Node)
		if visited[u.id] {
			continue
		}
		visited[u.id] = true

		for _, edge := range u.edges {
			v := edge.to
			if !visited[v] && dist[v] == -1 || dist[u.id]+edge.cost < dist[v] {
				dist[v] = dist[u.id] + edge.cost
				heap.Push(pq, &Node{id: v, dist: dist[v]})
			}
		}
	}

	return dist
}

func main() {
	// 示例图结构
	graph := []Node{
		{id: 0, edges: []Edge{{to: 1, cost: 2}, {to: 2, cost: 3}}},
		{id: 1, edges: []Edge{{to: 3, cost: 4}}},
		{id: 2, edges: []Edge{{to: 1, cost: 1}, {to: 3, cost: 5}}},
		{id: 3, edges: []Edge{}},
	}

	start := 0
	distances := dijkstra(graph, start)
	fmt.Println("Shortest distances from node", start, "to all other nodes:")
	for i, d := range distances {
		fmt.Printf("Node %d: %d\n", i, d)
	}
}

这段代码实现了 Dijkstra 算法,并在 main 函数中给出了一个示例图。你可以根据需要修改图结构和起始节点。注意,这个实现假设图中没有负权重的边。如果图中存在负权重的边,你需要使用其他算法,如 Bellman-Ford 算法。

360智脑:

Dijkstra算法是一种用于在加权图中找到单源最短路径的算法。在这个问题中,我们需要对Dijkstra算法进行修改,以适应权重范围在0到W之间的边。我们将使用一个优先队列(最小堆)来存储节点和它们的距离值,并按照距离值的大小进行排序。

以下是使用Go语言实现的修改后的Dijkstra算法的代码:

package main

import (
	"container/heap"
)

type Edge struct {
	to     int
	weight int
}

type Graph struct {
	vertices []*Vertex
}

type Vertex struct {
	id       int
	distance int
	edges    []Edge
	index    int // The index of the vertex in the heap
}

type PriorityQueue []*Vertex

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].distance < pq[j].distance
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
	pq[i].index = i
	pq[j].index = j
}

func (pq *PriorityQueue) Push(x interface{}) {
	n := len(*pq)
	vertex := x.(*Vertex)
	vertex.index = n
	*pq = append(*pq, vertex)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	vertex := old[n-1]
	vertex.index = -1
	*pq = old[0 : n-1]
	return vertex
}

func NewGraph(numVertices int) *Graph {
	g := &Graph{make([]*Vertex, numVertices)}
	for i := range g.vertices {
		g.vertices[i] = &Vertex{id: i}
	}
	return g
}

func (g *Graph) AddEdge(from, to, weight int) {
	g.vertices[from].edges = append(g.vertices[from].edges, Edge{to: to, weight: weight})
}

func (g *Graph) Dijkstra(source int) {
	pq := make(PriorityQueue, len(g.vertices))
	for i := range g.vertices {
		pq[i] = g.vertices[i]
		pq[i].distance = 1<<31 - 1
		pq[i].index = i
	}
	pq[source].distance = 0
	heap.Init(&pq)

	for pq.Len() > 0 {
		u := heap.Pop(&pq).(*Vertex)
		for _, edge := range u.edges {
			v := g.vertices[edge.to]
			newDistance := u.distance + edge.weight
			if newDistance < v.distance {
				v.distance = newDistance
				heap.Fix(&pq, v.index)
			}
		}
	}
}

func main() {
	g := NewGraph(5)
	g.AddEdge(0, 1, 1)
	g.AddEdge(0, 2, 4)
	g.AddEdge(1, 2, 2)
	g.AddEdge(1, 3, 5)
	g.AddEdge(2, 3, 1)
	g.AddEdge(3, 4, 3)

	g.Dijkstra(0)

	for i, vertex := range g.vertices {
		println("Shortest distance from source to", i, "is", vertex.distance)
	}
}

这段代码首先定义了一个Edge结构体来表示图中的边,以及一个Vertex结构体来表示图中的节点。然后,我们创建了一个Graph结构体来存储所有的节点和它们之间的边。我们还实现了一个优先队列(最小堆)来存储节点和它们的距离值,并按照距离值的大小进行排序。

Dijkstra函数中,我们初始化优先队列,并将所有节点的距离值设置为无穷大(除了源节点)。然后,我们不断地从优先队列中取出距离值最小的节点,并更新它的邻居节点的距离值。如果发现更短的路径,我们就更新节点的距离值,并调整优先队列中的顺序。

最后,我们在main函数中创建了一个示例图,并调用了Dijkstra函数来计算从源节点到所有其他节点的最短路径。

智谱清言:

在带权重的有向图中,传统的Dijkstra算法适用于权重为非负整数的图。为了满足题目中时间复杂度为 O ( W V + E ) O(WV+E) O(WV+E) 的要求,我们可以使用一种称为“迭代加层”的变种算法。这种算法的核心思想是将权重分层处理,每次迭代处理一层权重,直到处理完所有权重。
以下是使用Go语言实现的修改后的Dijkstra算法:

package main
import (
	"container/heap"
	"fmt"
)
const (
	MaxWeight = 100 // 假设W的最大值为100,可以根据实际情况调整
)
type Edge struct {
	to   int
	weight int
}
type Graph struct {
	adjacencyList [][]Edge
}
func NewGraph(v int) *Graph {
	return &Graph{adjacencyList: make([][]Edge, v)}
}
func (g *Graph) AddEdge(from, to, weight int) {
	g.adjacencyList[from] = append(g.adjacencyList[from], Edge{to: to, weight: weight})
}
type Item struct {
	vertex int
	distance int
	index int // The index is needed by update and is maintained by the heap.Interface methods.
}
type PriorityQueue []*Item
func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].distance < pq[j].distance
}
func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
	pq[i].index = i
	pq[j].index = j
}
func (pq *PriorityQueue) Push(x interface{}) {
	n := len(*pq)
	item := x.(*Item)
	item.index = n
	*pq = append(*pq, item)
}
func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	old[n-1] = nil  // avoid memory leak
	item.index = -1 // for safety
	*pq = old[0 : n-1]
	return item
}
func (pq *PriorityQueue) update(item *Item, distance int) {
	item.distance = distance
	heap.Fix(pq, item.index)
}
func (g *Graph) DijkstraModified(s int) []int {
	v := len(g.adjacencyList)
	dist := make([]int, v)
	for i := range dist {
		dist[i] = MaxWeight * v // 初始化距离为无穷大
	}
	dist[s] = 0
	pq := make(PriorityQueue, 1)
	pq[0] = &Item{vertex: s, distance: 0}
	heap.Init(&pq)
	for pq.Len() > 0 {
		item := heap.Pop(&pq).(*Item)
		u := item.vertex
		for _, e := range g.adjacencyList[u] {
			v := e.to
			weight := e.weight
			if dist[u] + weight < dist[v] {
				dist[v] = dist[u] + weight
				heap.Push(&pq, &Item{vertex: v, distance: dist[v]})
			}
		}
	}
	return dist
}
func main() {
	g := NewGraph(5)
	g.AddEdge(0, 1, 1)
	g.AddEdge(0, 2, 4)
	g.AddEdge(1, 2, 2)
	g.AddEdge(1, 3, 2)
	g.AddEdge(2, 3, 3)
	g.AddEdge(3, 4, 2)
	dist := g.DijkstraModified(0)
	fmt.Println("Shortest distances from source vertex 0:")
	for i, d := range dist {
		fmt.Printf("Vertex %d: %d\n", i, d)
	}
}

这段代码实现了一个简单的图结构,并使用修改后的Dijkstra算法来计算从源结点 s 到所有其他结点的最短路径。这里假设了最大权重 W 为100,你可以根据实际的最大权重来调整 MaxWeight 的值。代码的时间复杂度接近于 O ( W V + E ) O(WV+E) O(WV+E),因为在每次迭代中,我们都在处理所有结点的所有边。

天工:

修改Dijkstra算法以适应特定权重的有向图

对于给定的权重函数 ( w:E→(0,1,2.…,W) ),我们可以修改Dijkstra算法来适应这种特定的权重范围。由于权重范围固定在 (0) 到 (W) 之间,我们可以利用这个特性来改进算法的效率,将时间复杂度优化到 (O(WV + E))。

在标准的Dijkstra算法中,我们使用优先队列来选择下一个要探索的顶点,这通常会导致 (O(E + V \log V)) 的时间复杂度。但在这里,由于边的权重有限,我们可以用一个大小为 (W + 1) 的数组来代替优先队列,从而达到 (O(WV + E)) 的时间复杂度。

下面是一个用Go语言实现的修改后的Dijkstra算法:

package main

import (
	"fmt"
)

func modifiedDijkstra(graph [][]int, W int, source int) []int {
	n := len(graph)
	dist := make([]int, n)
	for i := range dist {
		dist[i] = 1000000 // Initialize distances to a very large number
	}
	dist[source] = 0

	bucket := make([][]int, W+1) // Bucket for vertices based on their tentative distance

	// Initialize the bucket
	for v := 0; v < n; v++ {
		bucket[dist[v]] = append(bucket[dist[v]], v)
	}

	// Main loop
	for i := 0; i < W*n; i++ {
		// Get the smallest distance vertex from the bucket
		if len(bucket[0]) == 0 {
			break // No more vertices to process
		}
		u := bucket[0][0]
		bucket[0] = bucket[0][1:] // Remove the vertex from the bucket

		// Update distances of adjacent vertices
		for v := 0; v < n; v++ {
			if graph[u][v] != 0 {
				weight := graph[u][v]
				if dist[u]+weight < dist[v] {
					dist[v] = dist[u] + weight
					bucket[dist[v]] = append(bucket[dist[v]], v)
				}
			}
		}
	}

	return dist
}

func main() {
	// Sample graph represented as adjacency matrix
	graph := [][]int{
		{0, 2, 0, 6, 0},
		{0, 0, 3, 8, 0},
		{0, 0, 0, 0, 1},
		{0, 0, 0, 0, 5},
		{0, 0, 0, 0, 0},
	}
	W := 8
	source := 0
	dist := modifiedDijkstra(graph, W, source)
	fmt.Println("Shortest distances from source:", dist)
}

代码解释

  1. 初始化距离数组和桶:我们用一个大数初始化距离数组,除了源点,源点的距离设为0。我们创建一个 (W+1) 大小的桶数组,用于存储根据距离分类的顶点。

  2. 主循环:我们遍历 (W \times n) 次,每次从桶中取出距离最小的顶点,并更新其邻接顶点的距离。

  3. 更新距离和桶:如果通过当前顶点到达邻接顶点的路径更短,我们更新该顶点的距离,并将其放入新的桶中。

这个实现利用了权重范围的特性,避免了使用优先队列,从而优化了算法的时间复杂度。

chatgpt:

要修改Dijkstra算法以满足要求,你可以按照以下步骤进行:

  1. 创建一个结构体来表示图中的每个节点以及计算到达该节点的最短路径长度。
  2. 初始化一个优先队列(堆)来存储待处理的节点,每个节点的权重为到达该节点的最短路径长度。
  3. 修改Dijkstra算法的步骤:
    a. 从源节点开始,将源节点加入优先队列,并将到达该节点的最短路径长度设为0。
    b. 当优先队列不为空时,重复以下步骤:
    • 从优先队列中取出权重最小的节点u。
    • 对于节点u的每个邻居v,如果通过u可以获得更短的路径,则更新v的最短路径长度,并将v加入优先队列。
  4. 当优先队列为空时,所有节点的最短路径长度都已计算出来。

下面是用Go语言实现修改后的Dijkstra算法的示例代码:

package main

import (
	"container/heap"
	"fmt"
)

type Edge struct {
	target, weight int
}

type Node struct {
	id, dist int
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool { return pq[i].dist < pq[j].dist }
func (pq PriorityQueue) Swap(i, j int) { pq[i], pq[j] = pq[j], pq[i] }

func (pq *PriorityQueue) Push(x interface{}) {
	item := x.(*Node)
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

func Dijkstra(graph map[int][]Edge, source, W int) []int {
	dist := make([]int, len(graph))
	for i := range dist {
		dist[i] = W + 1
	}

	dist[source] = 0
	pq := make(PriorityQueue, 0)
	heap.Init(&pq)
	heap.Push(&pq, &Node{source, 0})

	for pq.Len() > 0 {
		node := heap.Pop(&pq).(*Node)

		for _, edge := range graph[node.id] {
			if alt := dist[node.id] + edge.weight; alt < dist[edge.target] {
				dist[edge.target] = alt
				heap.Push(&pq, &Node{edge.target, alt})
			}
		}
	}

	return dist
}

func main() {
	graph := map[int][]Edge{
		0: {{1, 1}, {2, 4}},
		1: {{2, 2}, {3, 5}},
		2: {{3, 1}},
	}

	source := 0
	W := 10
	shortestPaths := Dijkstra(graph, source, W)

	fmt.Println(shortestPaths)
}

在这个示例代码中,我们定义了一个包含有向边的图数据结构,并实现了修改后的Dijkstra算法。您可以将图数据结构和修改后的Dijkstra算法应用于您的具体问题中。

kimi:

要修改 Dijkstra 算法以处理带权重的有向图,其中边的权重可以是 0 到 (W) 之间的任何非负整数,我们需要考虑如何高效地处理这些权重。原始的 Dijkstra 算法使用优先队列来选择下一个要处理的顶点,其时间复杂度为 (O((V+E) \log V))。为了达到 (O(WV + E)) 的时间复杂度,我们可以使用一个稍微不同的方法,特别是当我们可以使用一个数组而不是优先队列时。

以下是修改后的 Dijkstra 算法的步骤,以及 Go 语言的实现:

  1. 初始化:创建一个数组 dist 来存储从源点 (s) 到每个顶点的最短路径距离。将 dist[s] 设置为 0,将所有其他 dist[v] 设置为无穷大(或一个非常大的数)。

  2. 松弛操作:对于每个顶点,检查通过当前顶点是否可以改善到任何其他顶点的距离。这是通过检查通过当前顶点的边,并更新目标顶点的距离来完成的。

  3. 迭代:重复松弛操作,直到没有更多的改进为止。这可以通过使用一个数组来跟踪已经处理过的顶点来完成,或者通过迭代所有顶点直到没有距离被更新。

以下是 Go 语言的实现:

package main

import (
	"fmt"
)

const (
	INF = 1 << 63 // 表示无穷大
)

type Graph struct {
	adj [][]int // 邻接表表示图
}

func NewGraph(n int) *Graph {
	return &Graph{adj: make([][]int, n)}
}

func (g *Graph) AddEdge(u, v, w int) {
	g.adj[u] = append(g.adj[u], w*(v+1)) // 将边 (u, v) 与权重 w 添加到图中
}

func (g *Graph) Dijkstra(s int) []int {
	n := len(g.adj)
	dist := make([]int, n)
	for i := range dist {
		dist[i] = INF
	}
	dist[s] = 0

	for v := 0; v < n; v++ {
		u := -1
		for i := 0; i < n; i++ {
			if dist[i] != INF {
				if u == -1 || dist[i] < dist[u] {
					u = i
				}
			}
		}
		if u == -1 {
			break
		}
		for _, e := range g.adj[u] {
			w, v := e/(u+1), e%(u+1)-1
			if dist[u]+w < dist[v] {
				dist[v] = dist[u] + w
			}
		}
	}

	return dist
}

func main() {
	g := NewGraph(5)
	g.AddEdge(0, 1, 1)
	g.AddEdge(0, 2, 2)
	g.AddEdge(1, 2, 3)
	g.AddEdge(1, 3, 1)
	g.AddEdge(2, 1, 2)
	g.AddEdge(2, 3, 4)
	g.AddEdge(3, 4, 2)
	g.AddEdge(3, 0, 5)
	g.AddEdge(4, 1, 1)

	dist := g.Dijkstra(0)
	fmt.Println("Shortest distances from vertex 0:")
	for v, d := range dist {
		if d == INF {
			fmt.Printf("v%d: INF\n", v)
		} else {
			fmt.Printf("v%d: %d\n", v, d)
		}
	}
}

这段代码实现了一个简单的修改后的 Dijkstra 算法,它使用一个数组而不是优先队列来跟踪最短路径。时间复杂度是 (O(WV + E)),其中 (W) 是权重的最大值,(V) 是顶点的数量,(E) 是边的数量。

混元:

为了实现一个时间复杂度为 O ( W V + E ) O(WV + E) O(WV+E) 的 Dijkstra 算法,我们可以使用桶排序(Bucket Sort)来优化优先队列的操作。以下是 Go 语言实现的代码:

package main

import (
	"fmt"
)

const MaxWeight = 10000 // 假设最大权重为10000

type Edge struct {
	to, weight int
}

func dijkstra(graph [][]Edge, source int) []int {
	dist := make([]int, len(graph))
	for i := range dist {
		dist[i] = MaxWeight
	}
	dist[source] = 0

	buckets := make([][]int, MaxWeight+1)
	for i := range buckets {
		buckets[i] = []int{}
	}
	buckets[0] = append(buckets[0], source)

	for i := 0; i <= MaxWeight; i++ {
		for _, u := range buckets[i] {
			for _, edge := range graph[u] {
				v := edge.to
				w := edge.weight
				if dist[u]+w < dist[v] {
					dist[v] = dist[u] + w
					buckets[dist[v]] = append(buckets[dist[v]], v)
				}
			}
		}
	}

	return dist
}

func main() {
	graph := [][]Edge{
		{{1, 4}, {2, 1}},
		{{3, 1}},
		{{1, 2}, {3, 5}},
		{},
	}

	source := 0
	dist := dijkstra(graph, source)

	fmt.Println("Shortest distances from source", source, "to all nodes:")
	for i, d := range dist {
		fmt.Printf("Node %d: %d\n", i, d)
	}
}

代码解释

  1. 初始化距离数组 dist

    • 将所有节点的距离初始化为 MaxWeight(一个足够大的值)。
    • 源节点的距离初始化为 0。
  2. 桶排序初始化

    • 创建一个大小为 MaxWeight + 1 的桶数组 buckets,每个桶存储具有相同距离的节点。
    • 将源节点放入距离为 0 的桶中。
  3. 主循环

    • 对于每个可能的距离 i(从 0 到 MaxWeight),遍历该距离桶中的所有节点。
    • 对于每个节点 u,遍历其所有邻接边 (u, v, w)
    • 如果通过 u 到达 v 的新距离比当前记录的距离更短,则更新 dist[v] 并将 v 放入新的距离桶中。
  4. 返回结果

    • 最终返回 dist 数组,其中包含从源节点到所有其他节点的最短距离。

时间复杂度分析

  • 桶排序:由于权重范围是 [0, W],桶排序的时间复杂度是 O ( W ) O(W) O(W)
  • 遍历所有边:每个节点和每条边都只被处理一次,因此总的时间复杂度是 O ( W V + E ) O(WV + E) O(WV+E)

这种方法特别适用于权重范围较小且固定的情况,能够显著提高 Dijkstra 算法的效率。

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

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

相关文章

RK3568 buildroot系统在安装popt出错的问题

RK3568 buildroot系统在安装popt出错的问题 简介 使用 buildroot 系统给 RK3568 制作系统的时候,编译系统到 popt 这个组件时,编译出错 故障现象 gzip: popt-1.16.tar.gz: not in gzip format 上面的报错就是说 gzip 认为这个压缩包不是可以识别的格式 问题复现 我们进…

996是性价比最低的工作方式,没有之一!

不知道从什么时候开始&#xff0c;“996”工作制&#xff08;即每周工作从早9点至晚9点&#xff0c;持续6天&#xff09;已经从网络热梗&#xff0c;变成了不少企业和职场人的“工作常态”。 尤其是现如今职场中越来越频繁的裁员降薪&#xff0c;为了保住一份工作&#xff0c;…

浅入深出之了解常见的用户登录校验

文章目录 一、Cookie-Session认证校验流程缺点 二、Token校验流程缺点 三、JWT校验流程 四、JWT令牌的实践使用JWT组成引入依赖生成令牌 前言 在讲解这个问题之前&#xff0c;我们要先搞清楚基本的用户登录流流程。 用户在web登录页面填写登录信息前端发送登录信息到后端后端接…

[红队apt]CHM电子书攻击/电子教程攻击

免责声明:本文用于了解攻击者的攻击手法&#xff0c;切勿用于不法用途 前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文主要整理当初电子书的时代&#xff0c;利用电子书攻击的操作 CHM电子书简介 这个在当初普遍用于做教程课件&#xff0c;软件说明等应用。…

音频响度归一化 - python 实现

在处理音频样本时&#xff0c;往往我们的音频样本由于录制设备&#xff0c;环境&#xff0c;人发音的音量大小的不同影响&#xff0c;会造成音频响度不统一&#xff0c;分布在一个不同的响度值域上。为了让语音模型更好的学习音频特征&#xff0c;就有必要对音频的响度进行归一…

android中byte[] buf没有结束符,new String(buf)会不会出错?

答案是&#xff1a;不会 看例子&#xff1a; 这和c是不一样的&#xff0c;不需要特别的在字符串后面添加一个\0结束.

誉天教育十月新班启航:开启技能升级之旅,抢占未来先机!

安全HCIP 晚班 2024/10/8 存储HCIE 晚班 2024/10/10 Linux云计算架构师 晚班周末班 2024/10/14 云服务HCIP 周末班 2024/10/26 云计算HCIP 周末班 2024/10/26 RHCE 周末班 2024/11/2 数通HCIE直通车 晚班 2024/11/4 AI大模型HCIE 晚班 2024/11/11 数通HCIE直通车…

C# String 类型:那些你可能不知道的秘密

前言 嗨&#xff0c;大家好&#xff01; 今天咱们来聊一聊一个看似简单却充满玄机的话题 —— String 类型。 字符串应该是所有编程语言中使用最频繁的一种基础数据类型。 在 C# 中&#xff0c;String 可谓是特别的存在&#xff1a;它是引用类型&#xff0c;存储在托管堆中…

插件生成XML

目录 1.数据库配置 2.在pom.xml中添加插件 3.generator文件配置 1.数据库配置 # 数据库配置 spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncodingutf8&useSSLfalseusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc…

双主轴车床的优势

双主轴车床作为现代制造业中的一项重要技术&#xff0c;其优势显而易见。下面我将从几个方面详细阐述双主轴车床的优势&#xff1a; ‌一、提高生产效率‌ ‌并行加工‌&#xff1a;双主轴车床最大的特点在于其能够同时在两个主轴上进行加工&#xff0c;这种并行加工方式使得在…

LCD -

LCD 目录 LCD 回顾 应用 - 1、首先将该LCD屏官方写好的三个文件添加进工程中的api文件夹中 - 2、找到LCD的初始化函数 - 3、在LCD屏幕上显示字符串 - 4、在LCD屏幕上显示图片 - 5、在LCD屏幕上显示汉字 例&#xff1a;在LCD屏幕上显示温湿度&#xff0c;时间代码 LC…

Unsupervised Deep Embedding for Clustering Analysis

0. 论文信息 标题&#xff1a;Unsupervised Deep Embedding for Clustering Analysis期刊&#xff1a;International Conference on Machine Learning作者&#xff1a;Junyuan Xie&#xff0c;Ross Girshick&#xff0c;Ali Farhadi机构&#xff1a;University of Washington&…

每日一题|3162. 优质数对的总数 I、II|因子分解、计数方法

第一题非常简单的暴力解法。 class Solution:def numberOfPairs(self, nums1: List[int], nums2: List[int], k: int) -> int:nums2_ [i * k for i in nums2]count 0for i in nums1:for j in nums2_:count 0 if i % j else 1return count 第二题的难度提升在数量级在10万…

[java毕业设计]免费分享一套SpringBoot+Vue电影推荐(电影网)系统【论文+源码+SQL脚本】,帅呆了~~

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue电影推荐(电影网)系统&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue电影推荐(电影网)系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 如今社会上各行各业&#xff0c;都喜欢用…

大数据新视界 --大数据大厂之大数据如何重塑金融风险管理:精准预测与防控

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

第十七篇——无穷小(三):用动态和极限的眼光看世界

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 这个世界从互联网盛行信息爆炸的时候&#xff0c;就已经进入了无限思维时…

前端环境搭建一览记录

文章目录 写在前面Nodejs下载Nodejs介绍Nodejs下载方式nvm安装:安装Homebrew&#xff08;安装器&#xff09;(打开终端&#xff0c;输入下面的脚本)安装nvm验证安装是否成功配置环境内容查看环境内容刷新配置 nvm 使用如何使用nvm ls 查看当前安装的版本nvm use versionId 切换…

鸿蒙开发之ArkUI 界面篇 二十八 ForEach

ForEach语法格式如下&#xff1a; ForEach(数组名字,(Item&#xff0c;index) >{item要做的事情}) 实现下图效果&#xff1a; 代码如下&#xff1a; Entry Component struct IndexTest {State titles:string[] [学鸿蒙,赢取白富美,走向人生巅峰,影音娱乐,海外旅游]build…

并发编程-ReentrentLock概念及使用

1.ReentrantLock概念 ReentrantLock 是 Java 中的一种可重入锁&#xff0c;属于 java.util.concurrent.locks 包。它提供了比 synchronized 关键字更灵活的锁机制&#xff0c;允许更复杂的线程同步控制。以下是 ReentrantLock 的一些关键概念和特点&#xff1a; 可重入性&…

Linux的Redis安装部署

Redis是一个nosql数据库,速度快,key-value型数据库 1.root用户执行 yum install -y epel-release 配置epel仓库 2.安装Redis 命令: yum install -y redis 3.启动服务: systemctl start redis 4.注意关闭firewalld防火墙, 5.进入Redis服务端redis-cli