When is a worker-to-shift graph bipartite by construction, and when must you actually test it?
answer
- ask what the vertices actually are
- typed sides versus peers in a relation
- can an edge ever join two workers?
- a shared id space can fabricate an edge
- if it must be tested, it can fail
basics
~20 sWhen the two sides are distinct entity types — workers and shifts — every edge crosses and bipartiteness holds by construction. When edges relate peers, worker against worker, it is a property you must test, and it can fail.
solid answer
~50 sTwo very different graphs get called the same thing. In the first, vertices are **typed**: workers on one side, shifts on the other, an edge meaning "this worker can cover this shift". No edge can join two workers, so the graph is bipartite by construction and a two-coloring sweep proves only what the model already guarantees. What matters there is guarding the construction — keep the two id spaces distinct or tag each vertex, because if the ids collide, one bad row silently creates a same-side edge and the assignment comes out wrong. In the second graph, vertices are peers and the edge is a relation among them: "these two workers must not share a shift". Bipartiteness is then a real question that can fail, and the odd cycle is the evidence you hand back. The call also picks your algorithm: matching on a general graph is heavier than on a bipartite one.
go deeper
Be able to say what the vertices and edges represent in a scheduling story, and notice whether an edge joins two things of the same kind or two things of different kinds.
Explain that a typed two-sided build makes the check redundant while a peer relation makes it a real question, and that the check costs one linear sweep either way.
Show the production instinct: guard the construction with distinct id spaces and an ingest assertion, and use the odd cycle as a diagnostic that names the offending rows.
Own the consequence of the modeling call — the two families need different matching algorithms and different failure conversations, so decide the model deliberately rather than discovering it from bad output.
## Two graphs that look alike and are not Almost every scheduling story can be drawn as a graph, but the drawings fall into two structurally different families, and a senior candidate is expected to name which one they are in before reaching for an algorithm. **Family 1 — bipartite by construction.** The vertices come from two distinct entity types and an edge always spans the types. Workers and shifts, with an edge meaning eligibility. Applicants and roles. Devices and slots. The two sides are given by the domain, not discovered: it is impossible, in a correct build, for an edge to join two workers, because an edge *means* an eligibility relation between one worker and one shift. Here the two-coloring sweep is not wrong, it is simply redundant — it will always answer yes, and that yes carries no information you did not already have. **Family 2 — bipartiteness is a hypothesis.** The vertices are peers of one type and the edge is a relation among them: "these two people must not be on the same shift", "these two vendors must not share a table", "these two jobs must not run on the same host". Now there is nothing forcing a two-way split to exist. Whether the population can be divided into two groups is exactly the bipartiteness question, and the answer is often no. Running the check is the whole job, and its failure is not a defect — it is a finding about the data. ## What to do in family 1 instead of checking Since the property is guaranteed by the model, the useful engineering is to make sure the model is what actually got built: - **Keep the sides explicit.** Store the two vertex sets separately, or carry a type tag on each vertex, rather than reconstructing the split later by guessing from ids. - **Do not let the id spaces collide.** The classic production failure is worker id 7 and shift id 7 mapping to the same vertex index. The graph silently gains an edge that joins two workers, or worse, fuses a worker and a shift into one vertex. Nothing crashes; the assignment just comes out wrong. - **Assert at the boundary.** If you want a runtime guard, assert on ingest that every edge has one endpoint of each type. That is an `O(E)` scan and it fails loudly at the offending row, which is far more actionable than a two-coloring clash discovered three stages downstream. - **Keep the coloring sweep in your pocket for forensics.** If an assignment does come out nonsensical and you suspect a build bug, running the two-coloring over the constructed graph and printing the odd cycle names the rows that broke the typing. That is the one time the check earns its keep in family 1. ## What to do in family 2 Run the check per component, and treat both outcomes as deliverables: - **Yes**: the coloring *is* the answer — the two groups, ready to hand over. If the downstream step is a matching between those groups, you have now legitimately manufactured a family-1 graph out of a family-2 one. - **No**: report the odd cycle, not just the boolean. "These five people are mutually constrained in a ring, so no two-way split exists" is something an operations owner can act on; "infeasible" is not. Expect the follow-up question of what to do next, and be honest that removing one conflict from one odd cycle may leave other odd cycles behind, so it is an iterative negotiation rather than a one-step repair. ## Why the modeling call changes the algorithm This is the part that makes the distinction more than pedantry. Matching algorithms written for bipartite graphs rely on the two-sided structure — they grow alternating paths from one side and the structure guarantees those paths behave. Feed such a routine a graph with same-side edges and you do not get a clean rejection; you get output whose optimality guarantee simply does not hold. Maximum matching on a *general* graph is a genuinely different and heavier algorithm — the blossom construction exists precisely to handle the odd cycles that bipartite graphs cannot contain. So "is this bipartite?" is not a validation step bolted on before the real work; it decides which family of algorithm the problem belongs to. ## And a boundary worth stating Bipartiteness is a **precondition** for bipartite matching, never a guarantee that a satisfying assignment exists. A graph can be perfectly bipartite and still have no way to give every worker a shift — if six workers are all eligible only for the same two shifts, the structure is fine and the assignment is impossible. Existence of a complete assignment is governed by a separate condition on how many distinct neighbours each subset of one side has. Candidates who conflate the two answer "yes, it's bipartite" to a question that was really about feasibility.
- An assignment run produced nonsense and you suspect the graph build — how does a two-coloring help?Run it over the constructed graph. In a typed model the sweep must return bipartite, so a clash proves the build violated the typing, and the odd cycle certificate names the vertices involved — usually pointing straight at colliding id spaces. Longer term, assert the typing on ingest instead: it is one `O(E)` scan and it fails at the offending row.
- The conflict graph fails the test. What do you tell the scheduling owner?That two groups are provably impossible, and hand over the odd cycle as the minimal set of people whose mutual constraints cause it. The realistic options are adding a third group or relaxing one constraint inside that cycle — and be clear that dropping one edge can leave other odd cycles, so it may take more than one round.
- Does bipartiteness guarantee that every worker can be given a shift?No. Bipartiteness only says the two-sided structure exists; it says nothing about capacity. Six workers eligible only for the same two shifts form a perfectly bipartite graph with no complete assignment. Feasibility depends on whether every subset of one side has at least as many distinct neighbours on the other, which is a separate condition to check.
saying these in an interview costs you the question
- Runs a two-coloring check on a graph that is bipartite by definition
- Assumes any graph handed to a matching routine is bipartite
- Merges both entity types into one id space with no type tag
- Treats a failed check as a code bug rather than a real conflict
- Thinks general matching is bipartite matching with more edges
- Claims bipartite structure guarantees everyone gets assigned