N × N grid of lights, each one either on or off. The grid can be manipulated by pressing any one light on the grid, toggling the light - however, when a given light is pressed, all lights that are edge-wise adjacent to the pressed light also get toggled.
Consider anGiven an initial configuration, one might be interested in a sequence of moves that turns all of the lights on the board off, or more simply, whether such a sequence exists or not. For example, the following 5 × 5 grid can be solved by pressing the five numbered squares in their labeled order:
As surprising as it may seem, this second board is provably unsolvable. There is no sequence of moves in existence that turns all of the lights off:
Grid configurations will be represented as a series of lines in a text file. The first line will be a single integer, N , specifying the size of the grid. The following N lines will specify the contents of the grid, where ' # ' characters indicate lights that are on, and ' . ' characters indicate lights that are off. The two grid configurations above would be encoded as:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Clicking lights.txt will trigger a download of a ~300KB zip file, which contains a text file named "lights.txt". The text file contains, in the specified format, 1 0 0 0 0 light grids, with sizes 5 ≤ N ≤ 1 6 . Precisely X of these grids are solvable.
Find X .
Note : An efficient program can find X in well under one minute. If your program is taking hours to complete, you may need to rethink your approach.
This section requires Javascript.
You are seeing this because something didn't load right. We suggest you, (a) try
refreshing the page, (b) enabling javascript if it is disabled on your browser and,
finally, (c)
loading the
non-javascript version of this page
. We're sorry about the hassle.
With linear algebra , runtime about 2 seconds.
For a grid n × n , let's consider P and S , two F 2 -vector space of dimension n 2 , one dimension for each light/button of the grid.
A vector in P represents which button are Pressed (value 1) or not (value 0). A vector in S represents which lights are Switched on (value 1) or off (value 0).
If n = 2 , p = ⎝ ⎜ ⎜ ⎛ 1 0 1 1 ⎠ ⎟ ⎟ ⎞ ∈ P represents pressing on buttons 1, 3 and 4. s = ⎝ ⎜ ⎜ ⎛ 0 1 1 0 ⎠ ⎟ ⎟ ⎞ ∈ S represents lights 2 and 3 being switched on.
Let A be a matrix of dimension n 2 × n 2 such that if p ∈ P and A ⋅ p = s , then s ∈ S is the list of lights that have been switched. The i t h column of A has 1 for each light that is switched by pressing button i .
If n = 2 , A = ⎝ ⎜ ⎜ ⎛ 1 1 1 0 1 1 0 1 1 0 1 1 0 1 1 1 ⎠ ⎟ ⎟ ⎞ and for example, A ⋅ ⎝ ⎜ ⎜ ⎛ 1 0 1 1 ⎠ ⎟ ⎟ ⎞ = ⎝ ⎜ ⎜ ⎛ 0 0 1 0 ⎠ ⎟ ⎟ ⎞ , which means that pressing buttons 1, 3 and 4 switches light 3.
Now, given a grid s of lights, the problem is to find a vector p ∈ P such that A ⋅ p = s . (It's always possible if A in invertible in F 2 , which is the case for n = 1 , 2 , 3 , 6 , 7 , 8 , 1 0 , 1 2 , 1 3 , 1 5 , … ).
I tried to solve each of the 4'209 grids on 10'000 with non invertible matrix, but it took several minutes and didn't give the right answer.
I then tried to solve once for each n by changin the matrix to row echelon form, so as to get conditions on s . That worked well and took 1 second to compute the matrixes and 1 second to check each grid.
Step 1: creating matrixes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Step 2: Changing to row echelon form and finding conditions on lights to turn off for a solution to exist.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
Step 3: Checking if a grid satisfies conditions to have a solution
1 2 3 4 5 6 7 8 9 10 |
|
Step 4 Initialize, read file and check grids
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Problem Loading...
Note Loading...
Set Loading...
Solving this problem involves making a number of critical observations which enable us to solve a much simpler problem, followed by solving the simpler problem really fast ten thousand times.
Observation 1: The order of moves does not matter.
For any move sequence, the state of any given light depends on the initial configuration, and the number of times it was toggled. The former is fixed, and the latter is additive based on the moves made, and since addition is commutative, this number is irrespective of the order of the moves.
Observation 2: Each light need only be pressed at most once.
Since we've established that the order of moves doesn't matter, we can reorder any solution's moves however we like without changing its impact. Note what happens if we put two moves on the same light right next to each other - the toggles made by the first move are canceled by the second one, making the solution identical to one where neither of those moves were made. We can repeat this process to show that any move sequence can be reduced to an equivalent sequence with at most one press per light, so those are the only solutions we need to explore.
With Observations 1 and 2, we've restricted the set of move sequences we must analyze to a finite number to determine whether a board is solvable. Unfortunately, this number is 2 N ⋅ N , which is in lifetime-of-the-universe territory for N = 1 6 . We need to discover more opportunities for efficiency.
Observation 3: The first row of moves in a solution uniquely determines all moves in all remaining rows.
What this means is, given a list of 'press' or 'don't press' for all buttons in the first row of a grid, we can explicitly figure out the rest of a working solution from that data. The procedure is simple:
So, to determine if a board is solvable, it suffices to consider all move sets we could make in the first row alone, and see if any of them lead to a solution by the procedure described.
Observations 1 through 3 are all that's needed to come up with a solution that will finish in many hours, which, while sub-par, is a perfectly legitimate approach.
For each board, try all 2 N move sets on the first row, procedurally mutate from each one, and see if any such move set leads to an empty grid. This will take O ( 1 0 0 0 0 ⋅ N 2 ⋅ 2 N ) time. We can do a lot better than this, though.
Observation 4: All solvable board states are reachable from each other.
This stems from the fact that all move sequences are invertible, and by the very same move sequence as well. The consequence of this is that the only solvable board states are those that are reachable from the empty board state.
The greater, more useful consequence, is the induced transitive property. For any board state b , and any board state c than can be reached from b , b is solvable if and only if c is solvable. We can use this truth to achieve great computational efficiency.
Recall that Observation 3 provided us with a way to check whether a given board state was solvable. Now, let C be the set of all boards for which only lights in the bottom row are on, if any. For each N , we will compute S N ⊆ C , the set of all c ∈ C that are solvable.
Note that in the procedure outlined in Observation 3, the steps taken are completely independent of the configuration of lights in the bottom row - we only ever consider the states of lights in the preceding rows when determining the moves to be made. Thus, in inspecting all possible top-row move sets and their deterministic followings for a given c ∈ C , we in fact inspect the case for all c ∈ C , since the prodecure is the same.
Since a move sequence is its own inversion, if a sequence of moves solves some c ∈ C , the same sequence also mutates the empty state into c . By considering all 2 N top-row move sets, and applying the procedure in Observation 3, we thus determine all c ∈ C that are reachable from the empty state, and therefore all c ∈ C that are solvable, which is S N .
So, for each N ∈ [ 5 , 6 , . . . , 1 6 ] , we can compute S N in O ( N 2 ⋅ 2 N ) time. Then, for each board b in the file input, we use the procedure in Observation 3 for the empty top-row move set to mutate the board into some c ∈ C . By the transitive property in Observation 4, b is solvable if and only if c ∈ S N . Since we precomputed all these sets, each b only costs O ( N 2 ) runtime, for a total of O ( 1 0 0 0 0 ⋅ N 2 ) runtime after precomputation.
The precomputation time turns out to be the bottleneck, with N = 1 6 being the most expensive component. However, reasonably efficient code can compute all S N in well under a minute, and the queries for the 1 0 0 0 0 grids take a mere fraction of a second in comparison.
When all is said and done, code will identify that 8 9 8 6 of the 1 0 0 0 0 boards are solvable, and the rest are not.
Of course, other solutions exist! This game is well known , and very well analyzed .
One alternative solution (which I have not checked for speed), involves solving the board by treating the moves as variables in Z 2 , and doing Gaussian Elimination. This runs in O ( 1 0 0 0 0 ⋅ N 6 ) time.
Bonus Trivia:
Interestingly enough, upon further analysis, I found that, of the possible N for this problem, only boards of size 5 , 9 , 1 1 , 1 4 , and 1 6 have unsolvable instances. That is to say, that if N is not one of those numbers, the board is guaranteed to be solvable, regardless of configuration!
Predictably, OEIS comes to the rescue, and the rabbit hole goes down to Chebyshev polynomials of the second kind . Mathematics is truly an extraordinary rabbit hole.