Пример #1
0
//输入邻接表,返回最小生成树的权。
//复杂度为O(E+VlogV),通常比Kruskal强。
//对有向图不适用,多路同权时选择有问题(不能倒着用,可能选错)。
func Prim(roads [][]graph.Path) (sum uint, fail bool) {
	var size = len(roads)
	sum = uint(0)
	if size < 2 {
		return 0, true
	}

	const FAKE = -1
	var list = graph.NewVector(size)
	for i := 1; i < size; i++ {
		list[i].Link = FAKE
	}
	list[0].Index, list[0].Link, list[0].Dist = 0, 0, 0
	var root = graph.Insert(nil, &list[0])

	var cnt int
	for cnt = 0; root != nil; cnt++ {
		var current = root
		root = graph.Extract(root)
		sum += current.Dist
		for _, path := range roads[current.Index] {
			var peer = &list[path.Next]
			if peer.Link == FAKE { //未涉及点
				peer.Index, peer.Link, peer.Dist = path.Next, current.Index, path.Dist
				root = graph.Insert(root, peer)
			} else if peer.Index != FAKE && //外围点
				path.Dist < peer.Dist { //可更新
				peer.Link = current.Index
				root = graph.FloatUp(root, peer, path.Dist)
			}
		}
		current.Index = FAKE //入围
	}
	return sum, cnt != size
}
Пример #2
0
//输入邻接表,返回两点间的最短路径及其长度(-1指不通)。
func DijkstraPath(roads [][]graph.Path, start int, end int) (
	Dist int, marks []int) {
	var size = len(roads)
	if start < 0 || end < 0 || start >= size || end >= size {
		return -1, []int{}
	}
	if start == end {
		return 0, []int{start}
	}

	const FAKE = -1
	var list = graph.NewVector(size)
	for i := 0; i < size; i++ {
		list[i].Link = FAKE
	}
	list[start].Index, list[start].Link, list[start].Dist = start, start, 0
	var root = graph.Insert(nil, &list[start])

	for root != nil && root.Dist != graph.MaxDistance {
		var current = root
		if current.Index == end {
			for idx := end; idx != start; idx = list[idx].Link {
				marks = append(marks, idx)
			}
			marks = append(marks, start)
			for left, right := 0, len(marks)-1; left < right; {
				marks[left], marks[right] = marks[right], marks[left]
				left++
				right--
			}
			return (int)(current.Dist), marks
		}
		root = graph.Extract(root)
		for _, path := range roads[current.Index] {
			var peer = &list[path.Next]
			if peer.Link == FAKE { //未涉及点
				peer.Index, peer.Link = path.Next, current.Index
				peer.Dist = current.Dist + path.Dist
				root = graph.Insert(root, peer)
			} else if peer.Index != FAKE { //外围点
				var distance = current.Dist + path.Dist
				if distance < peer.Dist {
					peer.Link = current.Index
					root = graph.FloatUp(root, peer, distance)
				}
			}
		}
		current.Index = FAKE //入围
	}
	return -1, []int{}
}
Пример #3
0
//输入邻接表,返回某点到各点的最短路径的长度(-1指不通)。
//复杂度为O(E+VlogV),已知最快的单源最短路径算法,对稀疏图尤甚。
//可以处理有向图,不能处理负权边。
func Dijkstra(roads [][]graph.Path, start int) []int {
	var size = len(roads)
	if size == 0 || start < 0 || start >= size {
		return []int{}
	}

	var result = make([]int, size)
	if size == 1 {
		result[0] = 0
		return result
	}

	const FAKE = -1
	var list = graph.NewVector(size)
	for i := 0; i < size; i++ {
		list[i].Link = FAKE
	}
	list[start].Index, list[start].Link, list[start].Dist = start, start, 0
	var root = graph.Insert(nil, &list[start])

	for root != nil && root.Dist != graph.MaxDistance {
		var current = root
		root = graph.Extract(root)
		for _, path := range roads[current.Index] {
			var peer = &list[path.Next]
			if peer.Link == FAKE { //未涉及点
				peer.Index, peer.Link = path.Next, current.Index
				peer.Dist = current.Dist + path.Dist
				root = graph.Insert(root, peer)
			} else if peer.Index != FAKE { //外围点
				var distance = current.Dist + path.Dist
				if distance < peer.Dist {
					//peer.Link = current.Index
					root = graph.FloatUp(root, peer, distance)
				}
			}
		}
		current.Index = FAKE //入围
	}

	for i := 0; i < size; i++ {
		if list[i].Dist == graph.MaxDistance {
			result[i] = -1
		} else {
			result[i] = (int)(list[i].Dist)
		}
	}
	return result
}
Пример #4
0
//输入邻接表,返回一个以0号节点为根的最小生成树。
func PrimTree(roads [][]graph.Path) ([]Edge, error) {
	var size = len(roads)
	if size < 2 {
		return []Edge{}, errors.New("illegal input")
	}
	var edges = make([]Edge, 0, size-1)

	const FAKE = -1
	var list = graph.NewVector(size)
	for i := 1; i < size; i++ {
		list[i].Link = FAKE
	}
	list[0].Index, list[0].Link, list[0].Dist = 0, 0, 0
	var root = graph.Insert(nil, &list[0])

	for {
		var current = root
		root = graph.Extract(root)
		for _, path := range roads[current.Index] {
			var peer = &list[path.Next]
			if peer.Link == FAKE { //未涉及点
				peer.Index, peer.Link, peer.Dist =
					path.Next, current.Index, path.Dist
				root = graph.Insert(root, peer)
			} else if peer.Index != FAKE && //外围点
				path.Dist < peer.Dist { //可更新
				peer.Link = current.Index
				root = graph.FloatUp(root, peer, path.Dist)
			}
		}
		current.Index = FAKE //入围
		if root == nil {
			break
		}
		edges = append(edges, Edge{root.Link, root.Index})
	}
	if len(edges) != size-1 {
		return edges, errors.New("isolated part exist")
	}
	return edges, nil
}