Abstract

Like Event Scheduling, but now every event has a value — instead of maximizing the count of non-overlapping events, maximize their total value.

  • Category: Dynamic Programming / Interval Scheduling (weighted variant)
  • Input: A list of events, each with a start time, finish time, and value
  • Output: The maximum total value achievable from a non-overlapping subset
  • Paradigm: Backtracking (naive) → Dynamic Programming (via memoization)
  • Typical use cases: resource allocation where jobs differ in priority/payoff, not just presence — plain Event Scheduling’s “maximize count” greedy strategy no longer works once events carry different values

Problem Specification

  • Instance: — start time, finish time, and value for each event.
  • Solution: A subset of events .
  • Constraints: No two events in overlap.
  • Objective: .
  • Goal: Maximize the sum.

Why the Old Greedy Strategy Fails

Event Scheduling’s Earliest-End-Time greedy strategy is optimal for maximizing count, but says nothing about value — a short, low-value event finishing early can easily block out a much more valuable event that would have overlapped it. Greedy has no way to “look ahead” and weigh that trade-off, which is exactly why this problem needs a different approach.


Candidate Strategies / Approaches

Backtracking ✘ (exponential)

Strategy: sort events by end time. Consider the last event to end, — including it isn’t necessarily good, so try both possibilities:

  1. Exclude : recurse on .
  2. Include : recurse on the set of all intervals that do not conflict with — more precisely, where is the last event to end before starts.

Algorithm 22 Weighted Event Scheduling

Input: list of events [I1,,In][I_1, \dots, I_n]

Output: list of events that does not overlap each other and maximizes the value

procedure BTWES(I1,,InI_1, \dots, I_n)

if n=0n=0 then

return 00

if n=1n=1 then

return value(I1)value(I_1)

Out = BTWES(I1,,In1)BTWES(I_1, \dots, I_{n-1})

Let IkI_k be the last event to end before InI_n starts

In = BTWES(I1,,Ik)+value(In)BTWES(I_1, \dots, I_k) + value(I_n)

return max(\max(Out,, In))

Out costs ; In costs .

Runtime (worst case):

No better than exhaustive search.

The Key Insight: How Many Distinct Calls Are There?

We make up to recursive calls — but every recursive call has the form for some . So there are at most genuinely different calls that ever occur: .

Key Idea

Of the up to recursive calls this algorithm makes, only are actually distinct — the exact same subproblems are being solved over and over along different branches. Memoization — storing and reusing each distinct answer, e.g. in a hashmap or array — is the fix. This is the seed of the full Dynamic Programming solution below.

Dynamic Programming ✔

Instead of top-down recursion with a cache, solve the same distinct subproblems bottom-up, smallest first, filling in an array directly.


Dynamic Programming Solution (The 8 Steps)

1. Define Sub-Problems and Corresponding Array

Hint

The sub-problems are often restatements of the original problem.

  • Original Problem: find the max value among all valid schedules of .
  • Sub-Problem: let be the max value among all valid schedules of .

2. What Are the Base Cases?

True for any input — the empty schedule has value 0.

3. Give Recursion for Sub-Problems (Case Analysis)

Hint

Break up the sub-problem into distinct cases.

  • Case 1: is not part of the max-value schedule .
  • Case 2: is part of the max-value schedule , where is the last event before event starts.

(with and , so both terms reference strictly smaller sub-problems.)

4. Order the Sub-Problems

Since each sub-problem depends only on sub-problems of strictly smaller index, order them from up to .

5. What Is the Final Output?

6. Put It All Together: Iterative Algorithm

Algorithm 23 Max Subset

procedure MaxSubset([I1,,In],[v(I1),,v(In)][I_1, \dots, I_n], [v(I_1), \dots , v(I_n)])

A[0]=0A[0] = 0//Step 2

for k=1nk = 1 \dots n do//Step 4

j=1j = 1//Step 3 start

while End(Ij)Start(Ik)End(I_j) \leq Start(I_k) do

j=j+1j = j+1

In = v(Ik)+A[j1]v(I_k) + A[j-1]

Out = A[k1]A[k-1]

A[k]=max(A[k] = \max(In,, Out))//Step 3 end

return A[n]A[n]//Step 5

Variables & Data Structures

NameTypePurpose
AArray, size A[k] holds the max value achievable using only events
jIndexFound via linear scan — the last event that finishes before starts
In, OutValuesThe two candidate values for A[k] — including or excluding

Helper Functions / Operations Used

  • Find (last non-conflicting event before ) — linear scan in the pseudocode above, worst case per call to the outer loop; see Drawbacks / Constraints for a faster alternative.

Proof of Correctness / Optimality

Claim: is the max value out of all valid schedules of .

  • Base case: (Step 2).
  • Inductive Hypothesis: is set correctly for all , for some .
  • Inductive Step (Step 3): consider .
    • Case 1 — is not in the max-value schedule: the best schedule using only is then just the best schedule using , so — correct by the Inductive Hypothesis.
    • Case 2 — is in the max-value schedule: every event that conflicts with (i.e. ) must be excluded, so the best schedule is ‘s value plus the best schedule using only the non-conflicting events : — correct by the Inductive Hypothesis, since .
  • Since every valid schedule falls into exactly one of these two cases, and , is the true maximum.

Time & Space Complexity Analysis

General Case

ComplexityNotes
TimeOuter loop runs times; each iteration’s while loop scanning for costs worst case, giving
SpaceThe array A holds one entry per event

Best / Worst / Average Case

  • Best / Worst / Average case: all with this implementation — the linear scan for runs regardless of how the events happen to be arranged.

Drawbacks / Constraints

  • The bound isn’t tight to the DP idea itself — it comes from the linear scan used to find inside the loop. If events are pre-sorted by finish time (already assumed here) and you additionally binary-search for against the sorted start times, this drops to total — the same order as sorting the events in the first place.
  • Doesn’t handle changing values/weights dynamically — like most DP solutions, this assumes the full input (including all values) is known up front; recomputation is needed if values change after the array is filled.
  • Not suitable for: finding the count-maximizing schedule when all values happen to be equal — Event Scheduling’s simpler greedy strategy is a better fit for that special case, since it doesn’t need the full array at all.

References / Links