Golang程序实现加权区间调度算法
加权区间调度问题涉及一组区间,每个区间都有一个相关联的权重。在本文中,我们将使用两种方法(递归和动态规划)在Go语言中实现加权区间调度算法。这个经典的优化问题涉及选择非重叠区间以获得最大总权重。
解释
递归方法
递归方法采用了直接而优雅的方法。它逐个检查每个区间,并考虑两种情况-是否包括当前区间或跳过它。该方法利用递归来探索所有可能的区间组合,并计算最大权重。尽管概念上很清晰,但对于较大的输入来说,由于存在重叠的子问题,可能不是最有效的方法。
动态规划方法
动态规划方法是对递归方法的优化。它利用了备忘录的原理,存储先前计算的结果,以避免重复计算。该方法构建了一个不同区间大小的最大权重表,并利用这些预先计算的值来有效地计算解决方案。相对于递归方法,它对于较大的数据集来说更加高效。
语法
func recursiveWeightedIntervalScheduling(intervals []Interval) int
该语法接受一个间隔的切片作为输入,并返回一个整数。它使用递归方法来找到非重叠间隔的最大总权重。该方法递归地探索所有可能的间隔组合,并选择总权重最高的组合。然而,对于大量的间隔来说,它可能效率较低,因为会进行重复计算。
算法
- 根据间隔的结束时间升序对间隔进行排序。
-
初始化一个大小为len(intervals)+1的动态编程表DP,其中DP[i]表示至第i个间隔的非重叠间隔的最大总权重。
-
将DP[0]设置为0,因为没有要考虑的间隔。
-
遍历间隔i中的每个间隔(从1开始)−
- 使用二分查找或线性搜索找到最后一个兼容的间隔j(其中j的结束时间小于或等于i的开始时间)。
-
计算包括当前间隔i与DP[j]的总权重,并将其赋值给DP[i]。
-
更新DP[i]为DP[i-1]和DP[i]之间的最大值,以考虑排除当前间隔的可能性。
- 使用二分查找或线性搜索找到最后一个兼容的间隔j(其中j的结束时间小于或等于i的开始时间)。
-
非重叠间隔的最大总权重将存储在DP[len(intervals)]中。
示例1
在这个例子中,我们有六个加权间隔,表示为开始时间、结束时间和相应的权重的集合。目标是找到非重叠间隔的最大总权重,即选择一组间隔,使得它们的时间不重叠,并且它们的权重之和最大化。该算法通过递归地探索所有可能的间隔组合,并选择总权重最高的组合来有效地解决了这个问题。
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
实际应用
项目管理
加权区间调度在项目调度中发挥作用,其中任务具有不同的重要性和时间段。通过选择一系列重要性最大且没有重叠的任务,该算法帮助项目经理优化任务执行,以获得更好的项目结果。
会议室预订
在企业环境中,调度会议或研讨会等活动至关重要。加权区间调度有助于高效地对活动进行优先排序和调度,确保重要活动得到安排,优化会议室资源利用。
结论
在本文中,我们使用递归和动态规划两种方法介绍了加权区间调度算法。递归方法使用递归来探索所有可能的区间组合,而动态规划方法为了提高效率而存储中间结果。