You are given unit-length segments and L-shaped pieces, where an L-shaped piece is two unit-length segments joined at a angle. You want to use ALL of the pieces — all segments and all L's, rotating them however you need — to form the grid lines of an grid. The segments make up the edges of the grid, and the grid ends up with cells inside. For example, four unit segments can make a square, which is a grid:
+-+
| | four unit segments -> a 1 x 1 grid
+-+Given and , output any valid and , or if it's not possible. (, up to test cases.)
- Construction — this is a constructive algorithm, so I have to come up with an idea.
- Look at the diagonals — a staircase of L's from the top-left to the bottom-right?
- There's probably a unique recursion.
- Come up with a conjecture.
- [Examine Examples] — including varied examples and extremes. [Work Backward]. [Write It Out].
- Eventually: matching, flows, edge cover.
IdeaWorking backward: how many edges does a grid even have?
To get started I tried some small examples — small values of and , and small grids — to get a feel for what the pieces can make.
If we have to use all the pieces, the total number of unit edges is fixed: each L contributes two edges and each segment contributes one, so the grid must have exactly
edges.
Instead of building up from the pieces, suppose we already had a finished grid. What would and have to be? For the sake of argument, let's say the grid has rows and columns of cells (rather than , just for my simplicity), and count its edges — say on a :
+-+-+-+
| | | | r = 2, c = 3
+-+-+-+ horizontal unit edges: 3 lines of length 3 -> c(r+1) = 9
| | | | vertical unit edges: 4 lines of length 2 -> r(c+1) = 8
+-+-+-+After drawing a few of these, it's pretty quick to see that an grid has horizontal unit edges and vertical unit edges, for a total of
So for a valid construction we at least need .
Expand and solve for : from we get
which must be a positive integer. So has to be a factor of , and gives the bound .
So one easy solution, maybe: try all possible , compute the associated , and check that it's an integer. The problem is these numbers are really, really big — can be up to million, and there are test cases, so trying all up to is way too slow. Okay. Now what?
IdeaPeeling off the L's looks like a matching
Before worrying about speed, I wrote up the Idea 1 loop — try all , take the first integer :
e = p + 2q
for r = 1 .. (e-1)/3:
if (e - r) mod (2r + 1) == 0:
c = (e - r) / (2r + 1)
output r, c; done
output -1— and ran it on the samples.
I think it was the third-to-last sample, , , where my code came out with an incorrect answer. It picks , : the number of edges is correct (), but my answer differed from the Sample Output.
Is a correct alternative answer for , — or is it actually wrong? And if it's wrong, why?
So let's play with the grid:
+-+-+-+-+-+-+-+
| | | | | | | | r = 1, c = 7: H = 14 horizontal edges
+-+-+-+-+-+-+-+ V = 8 vertical edgesThere are only vertical edges here. And if you look at how an L-piece has to sit, it occupies one horizontal and one vertical unit edge that physically touch at a point:
+-+
| an L: one horizontal edge + one vertical edge, sharing an endpointSo no matter how you arrange things, this grid can never host more than L's — and this test case has . My answer really was wrong: the number of edges can be correct while the L's still don't fit.
Peeling the L-pieces off a finished grid is choosing a matching in a bipartite graph: the horizontal edges are one group of nodes, the vertical edges are the other group, and there's an edge between them if they physically touch at a point (so they could form an L together). Using L-pieces means finding a matching of size .
That's helpful, except for the fact that matching is an even harder problem than the original problem. But it does help us think about it: we're trying to match horizontal edges with vertical edges. So when is a big matching possible?
This reminded me of Hall's matching theorem, which is a thing I learned in graph theory somewhere in school — I had to look it up. It says a perfect matching exists if and only if every subset of nodes on one side has a neighborhood at least as large as itself. The "only vertical edges" argument above is one subset of that: take ALL the horizontal edges — their neighborhood can't be bigger than the verticals that exist. Applying the theorem for real would mean checking every subset, so I didn't try to apply it exactly.
I also did a squarer example (), started drawing L's on the corners, and got a lot more matched. So the shape matters: long and elongated is bad, square-ish is good — and at the very least, you're blocked by whichever orientation you have less of: every L uses one horizontal and one vertical edge, so no matching can be bigger than .
For a fixed and , under what conditions can we place a matching of size in the grid? (In other words: what is the Hall-type matching condition for this particular graph?)
IdeaTry all r, with the matching conditionAC
So, the new algorithm: for each candidate and its , also compute and , and require
This condition is definitely necessary, because of the matching bound: every L uses one horizontal and one vertical edge. Whether it's sufficient I did not prove in contest. But the regularity of these grids felt pretty good — there are always lots of horizontals next to verticals, and there's not really a way to create a pathological case as long as the grid is square enough. I tried for a few minutes to prove it, didn't, and just took it as a conjecture.
The next question I had for myself: how do I search all these and fast enough? There are still way too many candidate 's.
By symmetry we only need to try — transposing the grid swaps with (and with ), so if any grid works, one with works. And once ,
so . That's about candidates even at — very fast over test cases.
e = p + 2q
for r = 1, 2, 3, ...:
if e - r < 2r + 1: break # c would be < 1
if e - r < r * (2r + 1): break # c would be < r (only need r <= c)
if (e - r) mod (2r + 1) != 0: continue
c = (e - r) / (2r + 1)
H = c * (r + 1); V = r * (c + 1)
if min(H, V) < q: continue
output r, c; done
output -1Once I felt confident in that, I submitted, and it was accepted. (Far too late — it took me way too long. But accepted.)
IdeaPost-contest: why is min(H, V) enough?
We're left with the final question: why is it that as long as both edge counts are at least , we can always use exactly L-pieces? That's what was left unproven in my analysis, and proving it is part of why I wanted to write this one up. So let's figure it out.
In an grid, the maximum number of L's that can be placed simultaneously (the maximum matching between horizontal and vertical edges) is exactly
The upper bound we already know: each L uses one edge of each orientation, so no matching can be bigger than .
For the construction, take without loss of generality, so the vertical edges are the rarer kind (), and let's match every vertical edge. Group the horizontal edges by column: column has of them (one per horizontal line), and each one can form an L with a vertical edge on the line to its left (line ) or to its right (line ).
Now hand them out column by column. Vertical line can only be served by column : pair its verticals there, and column still has one horizontal left over — hand it to line . Column then owes line only , and can hand two horizontals to line . The handoff grows by one each column — a little triangle — until some column is handing off all ; from then on, each column serves its right-hand line entirely and has one horizontal to spare. Let's watch it happen on , , peeling each matched L-piece out of the picture as we go. The full grid:
+-+-+-+-+
| | | | |
+-+-+-+-+
| | | | |
+-+-+-+-+Column 1: pair line 1's two verticals with two of column 1's horizontals, and the leftover horizontal sticks out — it takes line 2's upper vertical with it:
+ +-+-+-+
| | | three L's peeled: line 1 is gone,
+ +-+-+-+ and so is one vertical of line 2
| | | |
+ +-+-+-+Line 2 still owes one vertical; column 2 pays it, and now TWO of its horizontals stick out — they take all of line 3:
+ + +-+-+
| | three more L's: line 2 finished,
+ + +-+-+ line 3 gone entirely
| |
+ + +-+-+And now the handoff has saturated at : column 3 takes all of line 4, column 4 takes all of line 5, each with one horizontal to spare:
+ + + + +
+ + + + + every vertical is matched; the two spare
horizontals are all that's left
+ + +-+-+No edge is used twice — once it's matched, it's out of the picture. Every vertical line gets its matches, and the spare horizontals number exactly (here: ). So all verticals are matched, which meets the bound.
So take any and that my loop outputs. The number of edges is correct, and , so by the lemma there's a way to place L-pieces on the grid. Place them, then fill in every remaining edge with a plain unit segment — and the counts guarantee that's exactly the segments we have. So the conjecture was true, and the solution is fully correct.
Review
To build an grid out of exactly unit segments and L-pieces, let and be the grid's horizontal and vertical edge counts. You need the right number of edges, , and enough edges of each orientation, — and any satisfying both works. The path:
- Count the edges. Using every piece means the grid has exactly unit edges. An grid has horizontal edges and vertical edges, so we need . [1][2]
- Solve for . For a candidate , we get that , which must be a positive integer.
- See the L's as a matching. An L occupies one horizontal and one vertical edge sharing an endpoint, so placing L's is a size- matching between the horizontal and vertical edges. [3]
- The matching exists iff . Necessary because each L uses one edge of each orientation; sufficient because the column-by-column handout achieves a matching of size . [KQ] [4] [Lemma 1]
- Only try . Transposing the grid swaps and , so if any grid works, one with works — and then , so : about candidates at worst. Check each candidate for integrality and the min condition; print the first hit, or . [5]
References
Problem-solving techniques used:
Small examples, varied examples, and extremes all earned their keep here: the long thin grid (: horizontal edges, vertical) against the squarer ones is where the condition came from. And the most useful example of all was one I didn't pick myself — see Generate and Test below.
The input is and the answer is a grid. By flipping it — starting from a finished grid and counting what and would have to be — we can derive every equation in this problem.
Seeing L-placement as a bipartite matching between horizontal and vertical edges. Somewhat of a red herring — matching in and of itself is a harder problem than this one — but it framed the right question, and the condition dropped out of it.
Hall's matching theorem, from graph theory somewhere in school; I had to look it up. I never applied it exactly — I used it as intuition for why long thin grids fail.
Writing out the code to try all and running it on the samples is what found the that didn't work (, picking the grid). When you're examining examples and gen-testing, looking for examples that truly falsify a claim — or truly verify it — is also how you find the pattern of when it works and when it doesn't.
I never proved in contest that is enough. The grids felt regular enough that I took it as a conjecture, submitted, and proved it after.
Learning points:
- In the end, the solution was really easy. It's a construction problem, which often can feel daunting, and it took me longer than it should have. Ironically I think I had the right path the whole way — I just came to it slowly.
- The things I did well: looked at small examples and varied them, made the matching transformation, tried all , came up with the condition. The thing that would have sped me up: pursuing the extremes deliberately. "Not enough horizontal edges is obviously bad; not enough vertical edges is obviously bad" was available much earlier than I found it.
- Test your claims against examples that can actually kill them. The naive loop looked fine until a sample falsified it, and that one failing case (long thin grid) is what surfaced the real condition. A claim that has only seen friendly examples isn't tested yet.
- I did this problem at around 11 p.m. Not to make an excuse, but it's probably something to note: I should be taking contests in the morning, well-rested, maybe a shot of coffee right before. I suspect I would have gotten there faster. I don't know.
Topics:
- Constructive problems
- Bipartite matching / Hall's theorem
- Counting / algebra
- Enumeration with bounds