CS252 Algorithms Wednesday, 21 September 2022 + Questions + O(m + n) - Searching tip: O, Ω, ϴ are called "Landau notation" (or "Bachmann–Landau") - Big-oh with multiple variables f(x,y) = O(g(x,y)) if ∃ C > 0, N > 0 st x >= N and y >= N ==> f(x,y) <= Cg(x,y) - What does that mean for an arguably two-variable situation like Problem 1? + Gale-Shapely, other contexts - [all dramatically simplified--exactly n of each set, full pref lists] - jobs/workers - chair x in class y / students - agents/writers - tutors/tutees - mentors/mentees - bobsled pilot/brake operator - Mariokart Double Dash driver/backseat - ... - But check out the problems in Chapter 1. Matching happens between ships and ports, circuit inputs and outputs,... + Gale-Shapely correctness proof summary - Let's use jobs/workers, proposal->offer, engaged->hired - (p7, 1.1) After getting one offer, a worker remains hired - (p7, 1.3) GS terminates after at most n^2 iterations - (p8, 1.4) If job j is free, then there is a worker w that has not been offered j - (p8, 1.5) At the end, the set S is a perfect matching - (p8, 1.6) At the end, the set S is a stable matching + Data structures: what do we need to be able to do? - Pick a free job j that has offers left to make - Pick highest-ranked worker w not offered job j - Is worker w free? - Add a hiring contract (j,w) - Make job j free - To what job is worker w contracted? - Compare worker w's preferences for jobs j and j' + Data structures that do each of those in O(1) time - Try it (10 minutes) - Suggestion: have arrays J[1..n] of jobs and W[1..n] of workers identify jobs by index j in J identify workers by index w in W + Jeff's data structures yesterday (ask what he thinks today) Identify each Job by its index j in array J Identify each Worker by their index w in array W Job: int pref[1..n]: pref[k] = the kth-preferred worker int nextOffer: index into pref[] int worker: index of hired worker (0 means none) Worker: int rank[1..n]: rank[j] = worker's 1-based ranking of job j int job: index of job (0 means none) J: Job[] (identify a job by index j) W: Worker[] (identify a worker by index w) FreeJobs: linked list of job indexes - Pick a free job j (that has offers left to make) j = FreeJobs.pop() - Pick highest-ranked worker w not offered job j w = j.pref[j.nextOffer] - Is worker w free? w.job >= 1 - Add a hiring contract (j,w) J[j].worker = w W[w].job = j - Make job j free J[j].worker = 0 FreeJobs.push(j) - To what job is worker w contracted? W[w].job - Compare worker w's preferences for jobs j and j' W[w].rank[j] < W[w].rank[j'] + Other stuff of interest - regardless of the order of the jobs selected in the loop, you get the same matching (whoa!) - once you understand the core theorem, there are tons of variants - allow preference ties ("indifference") - allow different sized sets - allow a single "job" to hire multiple "workers" (CS match) - ... - Reading proofs is not like other reading - Correctness requires that an algorithm terminates - Small examples (plus tinkering) help you get the feel of an algorithm