Go语言实现加权区间调度算法


加权区间调度问题围绕着一组区间展开,每个区间都具有相关的权重。在本文中,我们将使用两种方法(递归和动态规划)在Go语言中实现加权区间调度算法。这个经典的优化问题涉及选择总权重最大的不重叠区间。

解释

递归方法

递归方法采用了一种直接而优雅的方法。它逐个检查每个区间,并考虑两种情况——是否包含当前区间或跳过它。此方法利用递归来探索所有可能的区间组合,计算最大权重。虽然概念清晰,但由于存在子问题重叠,对于较大的输入,它可能不是最有效的方法。

动态规划方法

动态规划方法是对递归方法的优化。它利用记忆化原则,存储先前计算的结果以避免冗余计算。此方法构建一个针对各种区间大小的最大权重表,并利用这些预先计算的值来有效地计算解决方案。它比递归方法更有效,尤其是在处理大型数据集时。

语法

func recursiveWeightedIntervalScheduling(intervals []Interval) int

语法以区间切片作为输入并返回一个整数。它使用递归方法来查找不重叠区间的最大总权重。此方法递归地探索所有可能的区间组合,并选择总权重最高的组合。但是,由于冗余计算,对于大量区间,它的效率可能较低。

算法

  • 根据区间的结束时间按升序排序区间。

  • 初始化大小为len(intervals)+1的动态规划表DP,其中DP[i]表示直到第i个区间的最大不重叠区间总权重。

  • 将DP[0]设置为0,因为没有区间需要考虑。

  • 迭代intervals中的每个区间i(从1开始)——

    • 使用二分查找或线性查找找到最后一个兼容区间j(其中j的结束时间小于或等于i的开始时间)。

    • 计算包含当前区间i以及DP[j]的总权重,并将其赋值给DP[i]。

    • 将DP[i]更新为DP[i]和DP[i-1]之间的最大值,以考虑排除当前区间的可能性。

  • 不重叠区间的最大总权重将存储在DP[len(intervals)]中。

示例1

在这个例子中,我们有六个加权区间,表示为开始时间、结束时间和相应的权重的集合。目标是找到不重叠区间的最大总权重,即选择一个区间子集,使得没有两个区间在时间上重叠,并且它们的权重之和最大化。Go语言中的递归加权区间调度算法通过递归地探索所有可能的区间组合并选择总权重最高的组合来有效地解决这个问题。

package main

import "fmt"

type Interval struct {
	start, finish, weight int
}

func schedule(intervals []Interval, currentIndex, prevFinish int) int {
	if currentIndex == len(intervals) {
		return 0
	}

	if intervals[currentIndex].start < prevFinish {
		return schedule(intervals, currentIndex+1, prevFinish)
	}

	includeCurrent := intervals[currentIndex].weight + schedule(intervals, currentIndex+1, intervals[currentIndex].finish)
	skipCurrent := schedule(intervals, currentIndex+1, prevFinish)

	return max(includeCurrent, skipCurrent)
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func main() {
	intervals := []Interval{
		{1, 4, 3},
		{3, 7, 5},
		{0, 6, 8},
		{5, 9, 2},
		{8, 12, 6},
		{10, 15, 4},
	}

	maxWeight := schedule(intervals, 0, 0)

	fmt.Println("Maximum total weight of non-overlapping intervals:", maxWeight)
}

func sortByFinish(intervals []Interval) {
	n := len(intervals)
	for i := 0; i < n-1; i++ {
		for j := 0; j < n-i-1; j++ {
			if intervals[j].finish > intervals[j+1].finish {
				intervals[j], intervals[j+1] = intervals[j+1], intervals[j]
			}
		}
	}
}

输出

Maximum total weight of non-overlapping intervals: 14

示例2

在这个例子中,我们有六个加权区间:[1, 4, 3],[3, 5, 2],[0, 6, 4],[5, 7, 1],[8, 9, 3]和[5, 9, 5]。Go语言中的动态规划加权区间调度算法用于查找不重叠区间的最大总权重。对于给定的输入区间,发现不重叠区间的最大总权重为14。

package main

import (
	"fmt"
	"sort"
)

type Interval struct {
	start, end, weight int
}

func latestNonOverlapping(intervals []Interval, i int) int {
	for j := i - 1; j >= 0; j-- {
		if intervals[j].end <= intervals[i].start {
			return j
		}
	}
	return -1
}

func findMaxWeight(intervals []Interval) int {
	sort.Slice(intervals, func(i, j int) bool {
		return intervals[i].end < intervals[j].end
	})

	n := len(intervals)
	dp := make([]int, n)
	dp[0] = intervals[0].weight

	for i := 1; i < n; i++ {
		nonOverlap := latestNonOverlapping(intervals, i)
		if nonOverlap != -1 {
				dp[i] = max(dp[i-1], dp[nonOverlap]+intervals[i].weight)
		} else {
			dp[i] = max(dp[i-1], intervals[i].weight)
		}
	}

	return dp[n-1]
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func main() {
	intervals := []Interval{
		{1, 4, 3},
		{3, 5, 2},
		{0, 6, 4},
		{5, 7, 1},
		{8, 9, 3},
		{5, 9, 5},
	}

	maxWeight := findMaxWeight(intervals)
	fmt.Println("Maximum total weight of non-overlapping intervals:", maxWeight)
}

输出

Maximum total weight of non-overlapping intervals: 8

现实生活中的应用

项目管理

加权区间调度用于项目调度,其中任务具有不同的重要性和时间范围。通过选择一系列具有最大组合重要性和无重叠的任务,该算法帮助项目经理优化任务执行,以获得更好的项目成果。

会议室预订

在企业环境中,安排会议或研讨会等活动至关重要。加权区间调度有助于高效地优先安排和安排活动,确保重要活动得到安排,优化会议室的资源使用。

结论

在本文中,我们研究了使用两种方法(递归和动态规划)的加权区间调度算法。递归方法使用递归来探索所有可能的区间组合,而动态规划方法存储中间结果以提高效率。

更新于:2023年9月5日

浏览量:159

开启你的职业生涯

完成课程获得认证

开始学习
广告