G27
Self-checkedTier 1 10 min readalgo.greedy-scheduling-knapsack

Activity selection and fractional knapsack

Three classic greedy algorithms with their proofs: activity selection (earliest finish first, why earliest start and shortest first fail), the fractional knapsack (best value per unit weight first, why the same rule fails for 0/1 knapsack), and job sequencing with deadlines and profits; also interval partitioning (minimum number of rooms equals the maximum overlap). Running times and worked GATE-style instances.

Why it exists

Three problems show what a correct greedy algorithm looks like, and one of them shows what happens when the same idea is applied where it does not work. Activity selection (schedule the most non-overlapping jobs) and the fractional knapsack (fill a bag with the most valuable cuttable goods) are solved exactly by a simple rule and a sort; the 0/1 knapsack (items cannot be cut) has the same rule and is not solved by it. GATE asks for the greedy rule, the running time, the selected set for a given instance, and why a plausible rule fails.

Prerequisites

You need the greedy-choice property and the exchange argument (greedy method).

Precise definitions

Activity selection. Activities 1,…,n1, \ldots, n, activity ii occupying the half-open time interval [si,fi)[s_i, f_i). Two activities are compatible if their intervals do not overlap (one may start exactly when the other finishes). Choose a largest set of mutually compatible activities.

Interval partitioning. The same activities must all be performed, each in a "room"; activities in one room may not overlap. Find the fewest rooms.

Fractional knapsack. A bag holds weight WW. Item ii has weight wiw_i and value viv_i, and any fraction xi∈[0,1]x_i \in [0, 1] of an item may be taken (worth xivix_i v_i and weighing xiwix_i w_i). Maximise ∑xivi\sum x_i v_i subject to ∑xiwi≤W\sum x_i w_i \le W.

0/1 knapsack. The same, but each item is taken completely or not at all (xi∈{0,1}x_i \in \{0, 1\}).

Job sequencing with deadlines. nn jobs, each needing one unit of time on one machine, job ii with a deadline did_i (it must be finished at time did_i or earlier, that is, started in one of the slots 1,…,di1, \ldots, d_i) and a profit pip_i earned only if it meets its deadline. Choose and order jobs for maximum total profit.

How it works

Activity selection

Rule: sort by finish time; take the first activity; then repeatedly take the next activity that starts no earlier than the finish of the last chosen one. The animation runs the real code on nine activities already sorted by finish time: chosen ones turn green, rejected ones (overlapping the last chosen) fade.

Activity selection: always take the compatible activity that finishes first

Real run

C source

1#include <stdio.h>
2
3/* activities 0..n-1 are sorted by finish time: activity i runs from s[i] to f[i];
4 chosen[i] is set to 1 or 0; returns the number of activities chosen */
5int select_activities(const int s[], const int f[], int n, int chosen[]) {
6 int count = 1;
7 int last = 0;
8 chosen[0] = 1;
9 for (int i = 1; i < n; i++) {
10 if (s[i] >= f[last]) {
11 chosen[i] = 1;
12 count++;
13 last = i;
14 } else {
15 chosen[i] = 0;
16 }
17 }
18 return count;
19}

Start s[i]

1
0
2
1
0
2
4
3
5
4
3
5
6
6
8
7
11
8

Finish f[i]

3
0
5
1
6
2
7
3
8
4
9
5
10
6
11
7
13
8

chosen[i] (1 = chosen, 0 = rejected)

0
1
2
3
4
5
6
7
8

State

no activity chosen yet

Blue = the position this step is working on, amber = a position being compared, red = positions just swapped, green = finished or in its final place, a filled blue cell = a value just placed, faded = not part of the structure at this step.

Step 1

Nine activities, sorted by finish time. Choose as many mutually compatible (non-overlapping) activities as possible.

1 / 11
Nine activities, already sorted by finish time, are set up by hidden driver code. select_activities() is the exact code that runs. Green = chosen, faded = rejected because it overlaps the last chosen activity. Produced by: real execution: every array, stack, matrix and list in the picture is read from the running program's memory at each step. Apple clang version 21.0.0 (clang-2100.1.1.101). gcc -O0 -o prog prog.c && ./prog

Why earliest finish. Choosing the activity that finishes first leaves the largest possible remaining time. Proof (exchange). Let aa be the activity with the earliest finish time and OO any optimal solution, with first activity bb (in the order of finish). Since fa≤fbf_a \le f_b and everything else in OO starts at or after fbf_b, replacing bb by aa keeps OO compatible and of the same size: an optimal solution contains aa. What remains is the same problem on the activities that start at or after faf_a (optimal substructure), so by induction the greedy algorithm is optimal. ■\blacksquare

Other plausible rules fail. Each of them was tried against the exact optimum (found by trying all subsets).

Three greedy rules for activity selection: start

Computed by a script, not typed
ruleinstance 1: A(0,10) B(1,2) C(3,4)instance 2: A(0,5) B(4,6) C(5,10)verdict
earliest start first
shortest first
earliest finish first

Step 0

Activities are chosen in the order of a rule, skipping any that overlaps one already chosen. Only the rule 'earliest finish first' is optimal; the other two fail on one of these two small instances. The optimum is found by trying every subset.

0 / 3
computed by script: the quantities are measured by running C, or evaluated, one row at a time. python3 scripts/gen-algo-greedy-traces.py

Earliest start first is blocked by one long activity; shortest first can pick a short activity in the middle that overlaps two others; fewest conflicts first also fails (a counterexample with at most eleven activities was found by search). Only earliest finish first is right.

Running time. Sorting by finish time: Θ(nlog⁡n)\Theta(n \log n); the single scan afterwards: Θ(n)\Theta(n). If the activities are already sorted the algorithm is Θ(n)\Theta(n).

Interval partitioning. Sort the activities by start time; give each to any room that is free, opening a new room only when all are busy. The number of rooms equals the maximum number of activities running at the same time (the depth): it is at least that (all of those need different rooms) and the algorithm never opens a room unless that many are running. Time Θ(nlog⁡n)\Theta(n \log n).

Fractional knapsack

Rule: sort the items by value per unit weight, largest first; take whole items while they fit; take a fraction of the first item that does not fit; stop. The animation fills a bag of 3030 units with four items of ratios 8,6,5,38, 6, 5, 3.

Fractional knapsack: fill the bag with the best value per unit weight first

Real run

C source

1#include <stdio.h>
2
3/* items 0..n-1 are sorted by value per unit weight, largest first;
4 taken[i] receives the weight of item i that goes into the bag; returns the total value */
5double fractional_knapsack(const int w[], const int v[], int n, int capacity, int taken[]) {
6 double total = 0;
7 int left = capacity;
8 for (int i = 0; i < n; i++) {
9 int t = w[i] < left ? w[i] : left;
10 taken[i] = t;
11 total += (double)v[i] * t / w[i];
12 left -= t;
13 }
14 return total;
15}

Weight w[i]

12
0
8
1
20
2
10
3

Value v[i]

96
0
48
1
100
2
30
3

Value per unit weight

8
0
6
1
5
2
3
3

Weight taken

0
1
2
3

State

room left in the bag = 30, value collected so far = 0.0

Blue = the position this step is working on, amber = a position being compared, red = positions just swapped, green = finished or in its final place, a filled blue cell = a value just placed, faded = not part of the structure at this step.

Step 1

Four items and a bag that holds 30 units. Items may be cut: any fraction of an item can be taken.

1 / 7
Four items sorted by value per unit weight (8, 6, 5, 3) and a capacity of 30 are set up by hidden driver code. fractional_knapsack() is the exact code that runs. Produced by: real execution: every array, stack, matrix and list in the picture is read from the running program's memory at each step. Apple clang version 21.0.0 (clang-2100.1.1.101). gcc -O0 -o prog prog.c && ./prog

Why it is optimal. Suppose an optimal filling takes some of an item with a lower ratio while a higher-ratio item is not fully taken. Remove a little weight ε\varepsilon of the lower-ratio item and add the same weight of the higher-ratio one: the weight is unchanged and the value rises by ε(rhigh−rlow)>0\varepsilon(r_{\text{high}} - r_{\text{low}}) > 0. So no optimal solution can contain such a pair, and the greedy filling (which has no such pair) is optimal. The result was also confirmed against an exact linear programming search on random instances. ■\blacksquare

Running time. Θ(nlog⁡n)\Theta(n \log n) for the sort, then Θ(n)\Theta(n). (A selection algorithm for the item at the critical ratio makes it Θ(n)\Theta(n) in all.)

The 0/1 knapsack is different. With items of weight and value (10,60),(20,100),(30,120)(10, 60), (20, 100), (30, 120) and capacity 5050 the ratios are 6,5,46, 5, 4. The same rule takes the first two items (weight 3030, value 160160) and cannot fit the third; but the items 22 and 33 together (weight 5050) are worth 220220. The exchange argument fails because a fraction cannot be moved: the leftover capacity is wasted. The 0/1 knapsack has no known polynomial-time greedy algorithm; it is solved by dynamic programming in Θ(nW)\Theta(nW) time (dynamic programming problems), which is pseudo-polynomial.

Job sequencing with deadlines

Rule: consider the jobs in order of decreasing profit; put each into the latest free time slot not after its deadline; if there is none, reject it. The table runs it on six jobs.

Job sequencing with deadlines (unit-time jobs): start

Computed by a script, not typed
job (in order of decreasing profit)deadlineprofitdecisionslots 1, 2, 3total profit so far
job a
job c
job d
job b
job e
job f

Step 0

Each job takes one time unit and must finish by its deadline. Jobs are considered in the order of decreasing profit and put in the latest free slot not after the deadline. The final total is checked against an exhaustive search over all subsets of jobs.

0 / 6
computed by script: the quantities are measured by running C, or evaluated, one row at a time. python3 scripts/gen-algo-greedy-traces.py

Why it works. A set of jobs can all be scheduled exactly when, for every tt, at most tt of the jobs have deadline tt or earlier (they must all fit into the slots 1,…,t1, \ldots, t). Placing a job in the latest free slot keeps the early slots open for jobs with early deadlines; processing by profit makes the accepted set a maximum-profit feasible set (the feasible sets form a matroid, for which greedy by weight is optimal). The result for the table was checked against an exhaustive search over all subsets.

Running time. With a simple search for the latest free slot: O(n2)O(n^2) (for each job scan down from its deadline). With a disjoint-set structure for free slots: nearly O(nlog⁡n)O(n \log n) (the sort dominates).

Worked examples

EX 1Activity selection by hand

Easy

Activities (s,f)(s, f): (1,4),(3,5),(0,6),(5,7),(3,9),(5,9),(6,10),(8,11)(1,4), (3,5), (0,6), (5,7), (3,9), (5,9), (6,10), (8,11), already sorted by finish. Take (1,4)(1,4). (3,5)(3,5) starts at 3<43 < 4: reject. (0,6)(0,6): reject. (5,7)(5,7) starts at 5≥45 \ge 4: take; last finish 77. (3,9)(3,9): reject. (5,9)(5,9): reject. (6,10)(6,10): 6<76 < 7 reject. (8,11)(8,11): 8≥78 \ge 7 take. Chosen: (1,4),(5,7),(8,11)(1,4), (5,7), (8,11): three activities. If the list is not sorted by finish time, sort first.

EX 2Fractional knapsack by hand

Easy

Capacity 5050; items (weight, value): (10,60),(20,100),(30,120)(10, 60), (20, 100), (30, 120); ratios 6,5,46, 5, 4. Take the first completely (weight 1010, value 6060), the second completely (weight 3030, value 160160), and 2020 of the 3030 units of the third: value 2030⋅120=80\frac{20}{30} \cdot 120 = 80. Total 240240. The 0/1 optimum for the same data is 220220, so allowing cuts gains 2020.

EX 3Job sequencing

Medium

Jobs (deadline, profit): a(3,40),b(1,25),c(2,35),d(2,30),e(3,20),f(1,10)a(3, 40), b(1, 25), c(2, 35), d(2, 30), e(3, 20), f(1, 10). By decreasing profit: aa goes to slot 33; cc to slot 22; dd wants slot 22 (taken) and gets slot 11; bb wants slot 11 (taken): rejected; ee wants 3,2,13, 2, 1: all taken, rejected; ff rejected. Schedule: slot 11: dd, slot 22: cc, slot 33: aa. Profit 30+35+40=10530 + 35 + 40 = 105. Check: {b,c,a}\{b, c, a\} would give 100100, and no feasible set is better (exhaustive search).

EX 4Minimum number of rooms

Medium

Lectures [0,3),[1,4),[2,5),[4,7),[5,8)[0, 3), [1, 4), [2, 5), [4, 7), [5, 8). At time 22 three are running: [0,3),[1,4),[2,5)[0,3), [1,4), [2,5), so at least 33 rooms. Sorted by start, greedy assigns: [0,3)→R1[0,3) \to R_1, [1,4)→R2[1,4) \to R_2, [2,5)→R3[2,5) \to R_3, [4,7)→R2[4,7) \to R_2 (free at 44), [5,8)→R1[5,8) \to R_1 (free at 33). Three rooms, equal to the maximum depth.

EX 5Which rule, what time?

GATE level

(a) Activity selection with nn unsorted activities: Θ(nlog⁡n)\Theta(n \log n). (b) Fractional knapsack with nn items: Θ(nlog⁡n)\Theta(n \log n); 0/1 knapsack greedy by ratio: not optimal; 0/1 knapsack: Θ(nW)\Theta(nW) by dynamic programming. (c) Maximum number of activities compatible when activities (1,2),(2,3),(3,4),(1,10)(1,2), (2,3), (3,4), (1,10) are given: 33 (the first three; touching intervals are compatible). (d) Job sequencing, nn jobs, naive implementation: O(n2)O(n^2). (e) A greedy algorithm that picks the activity with the smallest duration: not always optimal.

Cheat box

Cheat box

  • Activity selection: sort by finish time, take every activity that starts at or after the last chosen finish. Θ(nlog⁡n)\Theta(n \log n). Optimal by exchange. Earliest start, shortest, fewest conflicts: wrong.
  • Interval partitioning: sort by start; rooms needed = maximum overlap (depth).
  • Fractional knapsack: sort by value/weight, take whole items, then a fraction. Θ(nlog⁡n)\Theta(n \log n). Optimal. 0/1 knapsack: greedy by ratio is not optimal; DP Θ(nW)\Theta(nW).
  • Job sequencing: decreasing profit, latest free slot ≤\le deadline; feasible set iff at most tt jobs have deadline ≤t\le t for every tt; O(n2)O(n^2) naive.
  • Compatible means sj≥fis_j \ge f_i (touching allowed).

Traps and GATE patterns

Connections

All three rely on the exchange argument of the greedy method. The 0/1 knapsack and its dynamic programming solution are in dynamic programming problems. The same style of greedy choice, always merge the two smallest, builds Huffman codes.

PYQs

2 previous year questions from your book. I re-solved each one myself (2 by running or simulating, 0 by reasoning only); the book's key is shown next to my answer. All PYQs

GATE 2005 · MCQ · 1 markQ48 · page 121 of the book
We are given 9 tasks T1, T2... T9. The execution
of each task requires one unit of time. We can
execute one task at a time. Each task Ti has a
profit Pi and a deadline di Profit Pi is earned if the
task is completed before the end of the d th unit of
time.
What is the maximum profit earned?
  • (a)147
  • (b)165
  • (c)167
  • (d)175
GATE 2005 · MCQ · 1 markQ49 · page 121 of the book
We are given 9 tasks T1, T2... T9. The execution
of each task requires one unit of time. We can
execute one task at a time. Each task Ti has a
profit Pi and a deadline di Profit Pi is earned if the
task is completed before the end of the d th unit of
time.
Are all tasks completed in the schedule that
gives maximum profit?
  • (a)All tasks are completed
  • (b)T1 and T6 are left out
  • (c)T1 and T8 are left out
  • (d)T4 and T6 are left out

Self-check

Question 1

Activities (1,3),(2,4),(3,5),(4,6)(1,3), (2,4), (3,5), (4,6): how many can be chosen and which?

Show answer

Two: (1,3)(1,3) and (3,5)(3,5) (touching is allowed); the greedy then rejects (2,4)(2,4), takes (3,5)(3,5) and rejects (4,6)(4,6). Also possible: (2,4),(4,6)(2,4), (4,6).

Question 2

Fractional knapsack, capacity 1515, items (weight, value) (5,50),(10,60),(10,100)(5, 50), (10, 60), (10, 100). What is the maximum value?

Show answer

Ratios 10,6,1010, 6, 10: take items 11 and 33 (5+10=155 + 10 = 15), value 150150.

Question 3

Why does greedy by value per weight fail for 0/1 knapsack?

Show answer

Leftover capacity cannot be filled by a fraction of an item; a combination with a lower-ratio item can use the capacity better (for example (10,60),(20,100),(30,120)(10,60),(20,100),(30,120) with capacity 5050: greedy 160160, optimum 220220).

Question 4

How many rooms does the interval-partitioning greedy use for a set of nn lectures (give it in terms of the lectures' overlaps)?

Show answer

The maximum number of lectures that run at the same time.

Revision card

One-screen revision

  • Activity selection: earliest finish first, Θ(nlog⁡n)\Theta(n \log n), exchange proof; other rules fail.
  • Rooms = maximum overlap (sort by start).
  • Fractional knapsack: value/weight descending, one fraction at the end, optimal; 0/1: not greedy, DP Θ(nW)\Theta(nW).
  • Job sequencing: profit descending, latest free slot; O(n2)O(n^2).

References

  • ·Cormen, Leiserson, Rivest, Stein, Introduction to Algorithms (3rd edition), Chapter 16 Greedy Algorithms (16.1 an activity-selection problem, 16.2 the fractional knapsack problem)
  • ·Kleinberg and Tardos, Algorithm Design, Chapter 4 (4.1 interval scheduling, 4.1 interval partitioning)
  • ·Horowitz, Sahni, Rajasekaran, Fundamentals of Computer Algorithms, Chapter 4 The Greedy Method (job sequencing with deadlines)

Verification

Activity selection by earliest finish equalled the brute-force optimum on 3000 random instances (n up to 8), while earliest start first and shortest first failed (small instances found by search, shown on the page) and the fewest-conflicts rule also failed on a random instance found by search. Interval partitioning used exactly the maximum overlap on 500 random instances. The greedy fractional knapsack value equalled the exact linear programming optimum, computed by enumerating every vertex, on 500 random instances; the 0/1 knapsack counterexample and the animation total (194) were recomputed. Job sequencing by profit with the latest free slot equalled an exhaustive optimum on 1500 random instances, and the feasibility test (for every t at most t jobs have deadline t or less) agreed with trying every order. The two animations are real runs of the C code shown. Job sequencing is not in the official GATE list but appears in textbooks and past papers; its running times are the standard ones. Textbook chapter references are from memory. SECOND PASS (2026-11-02, done by the assistant, not a human check): every Self-check question was solved before the printed answer was read and all agreed; the definitions, worked examples, cheat box and traps were read claim by claim and the numbers re-derived by hand or by a small script (loop counts, recurrences, merge and quicksort counts and averages, hash probes and load-factor formulas, DP tables, MST and shortest-path runs, Floyd matrices); long C programs were not re-read line by line (they are compiled and compared by npm run verify:c, and their printed outputs were checked against the prose); tables and animations are machine output and were read, not re-run; One Self-check question about the number of rooms was reworded because 'at most' was ambiguous. Status raised to self-checked; verified needs a textbook or human check.

last verified: never