Recently I was recommended the problem CERC'10 J — Justice for All. I really liked the solution I came up with and it's different from the editorial, so here's a blogpost talking about it.
Problem
You are given a number $$$n$$$ and you want to create a bipartite graph with $$$n$$$ perfect matchings, $$$1 \leq n \leq 10^6$$$.
The number of nodes in the graph shouldn't exceed $$$400$$$.
Main Idea
We want to build a kind of graph whose number of perfect matchings can be expanded.
If the graph has $$$x$$$ perfect matchings, we want to be able to expand it so that the new graph now has either $$$2x$$$ or $$$2x+1$$$.
If it's possible to do this, then we can use the binary representation of $$$n$$$ to create the graph.
Solution
Locking Mechanism
The idea for doubling is simple, we just need to add a graph with two matchings in such a way that it doesn't disturb the configurations that were previously there. Such graph with two matchings can simply be a square:
![](/predownloaded/70/5b/705b047a4c556d61a65c8c171837d4d45b46d249.png)
Now for doubling and adding one, we can keep the idea of adding a square, but after adding it we need some kind of locking mechanism that either forces a specific configuration of the whole graph or doesn't disturb the configurations that were already there.
We can see the idea of a locking mechanism on a small graph.
Without the locking edge, it has $$$2$$$ perfect matchings.
![](/predownloaded/b9/22/b922a608acc9af51091857bb573509c3a26e1afa.png)
With the locking edge, it has $$$3$$$ perfect matchings. When the locking edge is selected the configuration of the whole graph is forced, otherwise it's the same as if there was no locking edge.
![](/predownloaded/19/c7/19c7449e6ab2000a562b30334c34cde0d4efbac3.png)
This idea for one square can be extended to lock a chain of squares:
![](/predownloaded/f0/76/f076c5d1ca6871335e38c1dc466927e2e9072af3.png)
If the locking edge is selected, the configuration of the whole chain is locked. If it's not selected, each square is independent.
![](/predownloaded/07/46/0746c573f1a8273a86f331ce8290bf8d3d20f706.png)
Extending $$$x \rightarrow 2x+1$$$
Now we can see that these chains can be extended.
![](/predownloaded/68/91/689114950c9ed7acc1ed065fe01cae61532f3fd7.png)
By extending and adding a locking edge, the same previous scenarios can happen:
![](/predownloaded/8a/5b/8a5b5cfbeabc6037c0f26ef00739481650f54c68.png)
![](/predownloaded/8c/64/8c64e0ccb80a33d5aefa43082fecd1cd32c1f468.png)
So if the previous chain had $$$x$$$ perfect matchings, this extension now has $$$2x+1$$$.
Extending $$$x \rightarrow 2x$$$
By extending and not adding the locking edge, we just don't have the locked configuration:
![](/predownloaded/d1/30/d130e9b8641389cb7aa9293bcb161084e4fe9ea3.png)
If the chain had $$$x$$$ perfect matchings, this extension now has $$$2x$$$.
So this is it. We found a procedure that lets us extend a chain in the manner we wanted.
Construction
We start with a simple edge with $$$1$$$ perfect matching:
![](/predownloaded/c4/a7/c4a7095f54d1ba81478dc587a7ad8fe2652f4001.png)
If we have a graph with $$$x$$$ perfect matchings and we want to make it $$$2x$$$, we add a square without a locking edge:
![](/predownloaded/fe/ca/feca2158cd39d16c5082f938db5c72554ad88383.png)
If we have a graph with $$$x$$$ perfect matchings and we want to make it $$$2x+1$$$, we add a square with a locking edge:
![](/predownloaded/6f/dc/6fdcd2a38fb4a125a0015e8f6893416220c0f26a.png)
Analysis
We want the number of nodes to be less or equal to $$$400$$$.
This construction starts with $$$2$$$ nodes and adds $$$4$$$ for each bit in $$$n$$$ below the most significative.
So this solution has at most $$$4\lfloor \log_2(10^6) \rfloor+2 = 78$$$ nodes, which fits very comfortably below the limit.
Note: the official solution follows a similar idea, but adds 6 nodes for increasing by one and for doubling, resulting in $$$214$$$ nodes in the worst case
Code
The code for this is surprisingly short.
Here is an accepted submission (you may need coach mode to access it).
OTZ