Golang program to implement a weighted interval scheduling algorithm


The Weighted Interval Scheduling Problem revolves around a set of intervals, each having an associated weight. In this article, we will implement the Weighted Interval Scheduling algorithm in go, using two methods: Recursive and Dynamic Programming. This classic optimization problem involves selecting non-overlapping intervals with maximum total weight.

Explanation

Recursive Method

The Recursive Method takes a straightforward yet elegant approach. It examines each interval one by one and considers two scenarios − whether to include the current interval or skip it. This method utilises recursion to explore all possible combinations of intervals, calculating the maximum weight. While conceptually clear, it might not be the most efficient approach for larger inputs due to overlapping subproblems.

Dynamic Programming Method

The Dynamic Programming Method is an optimization over the recursive approach. It capitalizes on the principle of memoization, storing previously computed results to avoid redundant calculations. This method builds a table of maximum weights for various interval sizes and utilizes these precomputed values to efficiently compute the solution. It's more efficient than the recursive method, especially for larger datasets.

Syntax

func recursiveWeightedIntervalScheduling(intervals []Interval) int

The Syntax takes a slice of intervals as input and returns an integer. It uses a recursive approach to find the maximum total weight of non-overlapping intervals. This method recursively explores all possible combinations of intervals and selects the one with the highest total weight. However, it can be less efficient for a large number of intervals due to redundant calculations.

Algorithm

  • Sort the intervals based on their finish times in ascending order.

  • Initialize a dynamic programming table DP of size len(intervals)+1, where DP[i] represents the maximum total weight of non-overlapping intervals up to the ith interval.

  • Set DP[0] to 0, as there are no intervals to consider.

  • Iterate over each interval i in intervals (starting from 1) −

    • Find the last compatible interval j (where the finish time of j is less than or equal to the start time of i) using binary search or linear search.

    • Calculate the total weight of including the current interval i along with DP[j] and assign it to DP[i].

    • Update DP[i] to the maximum value between DP[i] and DP[i-1] to consider the possibility of excluding the current interval.

  • The maximum total weight of non-overlapping intervals will be stored in DP[len(intervals)].

Example 1

In this example, we have six weighted intervals represented as a collection of start times, finish times, and corresponding weights. The goal is to find the maximum total weight of non-overlapping intervals, i.e., to select a subset of intervals such that no two intervals overlap in time, and the sum of their weights is maximized. The Recursive Weighted Interval Scheduling algorithm in go efficiently solves this problem by recursively exploring all possible combinations of intervals and selecting the one with the highest total weight.

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]
			}
		}
	}
}

Output

Maximum total weight of non-overlapping intervals: 14

Example 2

In this example, we have six weighted intervals: [1, 4, 3], [3, 5, 2], [0, 6, 4], [5, 7, 1], [8, 9, 3], and [5, 9, 5]. The Dynamic Programming Weighted Interval Scheduling algorithm in go is employed to find the maximum total weight of non-overlapping intervals. For the given input intervals, the maximum total weight of non-overlapping intervals is found to be 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)
}

Output

Maximum total weight of non-overlapping intervals: 8

Real life implementations

Project Management

Weighted Interval Scheduling finds use in project scheduling, where tasks have varying importance and timeframes. By selecting a sequence of tasks with maximum combined importance and no overlap, this algorithm aids project managers in optimizing task execution for better project outcomes.

Conference Room Booking

In corporate environments, scheduling events like meetings or workshops is crucial. Weighted Interval Scheduling helps prioritize and schedule events efficiently, ensuring important activities are accommodated, optimizing resource use in conference rooms.

Conclusion

In this article, we have looked at the Weighted Interval Scheduling algorithm using two methods: Recursive and Dynamic Programming. The Recursive Method uses recursion to explore all possible combinations of intervals, while the Dynamic Programming Method stores intermediate results for efficiency.

Updated on: 05-Sep-2023

87 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements