Problem 669: The King's Banquet
View on Project EulerProject Euler Problem 669 Solution
EulerSolve provides an optimized solution for Project Euler Problem 669, The King's Banquet, with C++, Python, Java, and a step-by-step mathematical explanation.
Problem Summary Let \(F_1=F_2=1\) and \(F_{j+2}=F_{j+1}+F_j\). On the vertex set \(\{1,2,\dots,n\}\), we join \(u\) and \(v\) exactly when \(u+v\) is a Fibonacci number. The problem asks for the label at a specified place in a Hamiltonian path when \(n=F_{83}\). The crucial point is that for Fibonacci-sized graphs \(n=F_k\), the path used by the implementations is not found by search; it is given by a closed arithmetic rule. Mathematical Approach For graphs of size \(F_k\), the path can be described with modular arithmetic. The reason this works is that consecutive Fibonacci numbers are coprime, so stepping by \(F_{k-1}\) permutes the residue classes modulo \(F_k\). Step 1: Model the Banquet as a Fibonacci-Sum Graph Define $G_k=(\{1,2,\dots,F_k\},E),\qquad \{u,v\}\in E \iff u+v\in\{F_j:j\ge 1\}.$ A Hamiltonian path is an ordering \(a_1,a_2,\dots,a_{F_k}\) that uses every vertex exactly once and satisfies $a_i+a_{i+1}\in\{F_j:j\ge 1\},\qquad 1\le i \lt F_k.$ Because the graph is undirected, reversing such an ordering still gives a valid Hamiltonian path. The implementations therefore describe the path from the right end first and convert the requested left-side position only at the end....
Detailed mathematical approach
Problem Summary
Let \(F_1=F_2=1\) and \(F_{j+2}=F_{j+1}+F_j\). On the vertex set \(\{1,2,\dots,n\}\), we join \(u\) and \(v\) exactly when \(u+v\) is a Fibonacci number. The problem asks for the label at a specified place in a Hamiltonian path when \(n=F_{83}\). The crucial point is that for Fibonacci-sized graphs \(n=F_k\), the path used by the implementations is not found by search; it is given by a closed arithmetic rule.
Mathematical Approach
For graphs of size \(F_k\), the path can be described with modular arithmetic. The reason this works is that consecutive Fibonacci numbers are coprime, so stepping by \(F_{k-1}\) permutes the residue classes modulo \(F_k\).
Step 1: Model the Banquet as a Fibonacci-Sum Graph
Define
$G_k=(\{1,2,\dots,F_k\},E),\qquad \{u,v\}\in E \iff u+v\in\{F_j:j\ge 1\}.$
A Hamiltonian path is an ordering \(a_1,a_2,\dots,a_{F_k}\) that uses every vertex exactly once and satisfies
$a_i+a_{i+1}\in\{F_j:j\ge 1\},\qquad 1\le i \lt F_k.$
Because the graph is undirected, reversing such an ordering still gives a valid Hamiltonian path. The implementations therefore describe the path from the right end first and convert the requested left-side position only at the end.
Step 2: Write the Right-End Order as a Modular Walk
For \(m\ge 1\), let \(\rho_m\) be the unique integer with
$\rho_m \equiv mF_{k-1}\pmod{F_k},\qquad 1\le \rho_m \lt F_k.$
Then the right-to-left order is
$a_1=F_k,\qquad a_{2m}=\rho_m,\qquad a_{2m+1}=F_k-\rho_m,$
for every \(m\) for which the index exists. If \(F_k\) is even, the path simply ends with its final even term; for the target case \(F_{83}\) is odd, so all nonterminal terms after \(a_1\) come in even-odd pairs.
This is equivalent to the compact position formula used in the implementations. If \(r\) is the position counted from the right and \(m=\lfloor r/2\rfloor\), compute
$t \equiv mF_{k-1}\pmod{F_k},\qquad 0\le t \lt F_k,$
and interpret residue \(0\) as the vertex \(F_k\). Then
$v(r)=\begin{cases} F_k, & r=1,\\ t, & r\equiv 0 \pmod{2},\\ (F_k-t)\bmod F_k, & r\equiv 1 \pmod{2}. \end{cases}$
Step 3: Prove That Consecutive Vertices Are Adjacent
There are three kinds of neighboring pairs in the right-end description.
The opening edge is valid because
$a_1+a_2=F_k+\rho_1=F_k+F_{k-1}=F_{k+1}.$
Each even-odd pair is valid because
$a_{2m}+a_{2m+1}=\rho_m+(F_k-\rho_m)=F_k.$
Finally, between one pair and the next, we use
$\rho_{m+1}\equiv \rho_m+F_{k-1}\pmod{F_k}.$
So \(\rho_{m+1}\) is either \(\rho_m+F_{k-1}\) or \(\rho_m+F_{k-1}-F_k\), which gives
$a_{2m+1}+a_{2m+2}=(F_k-\rho_m)+\rho_{m+1}\in\{F_{k+1},F_{k-1}\}.$
All three possible sums, \(F_{k-1}\), \(F_k\), and \(F_{k+1}\), are Fibonacci numbers. Hence every consecutive pair in the constructed order is an edge of the graph.
Step 4: Prove That Every Vertex Appears Exactly Once
Since consecutive Fibonacci numbers are coprime,
$\gcd(F_{k-1},F_k)=1.$
Therefore multiplication by \(F_{k-1}\) permutes the nonzero residue classes modulo \(F_k\), so the values \(\rho_m\) are all distinct.
The complementary values \(F_k-\rho_m\) are also distinct. A collision between the two families would require
$\rho_m=F_k-\rho_j,$
which implies
$(m+j)F_{k-1}\equiv 0\pmod{F_k}.$
Because \(F_{k-1}\) is invertible modulo \(F_k\), this forces \(m+j\equiv 0\pmod{F_k}\). But in the relevant range we have \(1\le m+j \lt F_k\), so this cannot happen. Thus the construction uses each label exactly once and is a Hamiltonian path.
Step 5: Convert the Requested Position
The problem gives a position counted from the left, while the closed form is easiest from the right. If the path length is \(F_k\) and the requested left position is \(L\), then the corresponding right position is
$r=F_k-L+1.$
Since reversing the path preserves adjacency, evaluating \(v(r)\) gives the required knight directly.
Worked Example: \(n=13=F_7\)
Here \(F_{k-1}=8\). The modular residues are
$\rho_m \equiv 8m\pmod{13}\qquad(m=1,\dots,6),$
namely
$8,\ 3,\ 11,\ 6,\ 1,\ 9.$
So the right-end order is
$13,\ 8,\ 5,\ 3,\ 10,\ 11,\ 2,\ 6,\ 7,\ 1,\ 12,\ 9,\ 4.$
Reversing it gives the left-to-right order
$4,\ 9,\ 12,\ 1,\ 7,\ 6,\ 2,\ 11,\ 10,\ 3,\ 5,\ 8,\ 13.$
The consecutive sums are
$13,\ 21,\ 13,\ 8,\ 13,\ 8,\ 13,\ 21,\ 13,\ 8,\ 13,\ 21,$
all Fibonacci numbers, so the construction is visible on a small instance.
How the Code Works
The C++, Python, and Java implementations all follow the same arithmetic plan. They precompute Fibonacci numbers up to the required index, set \(n=F_{83}\), convert the requested left position \(10^{16}\) to the right-side index \(r=n-10^{16}+1\), and then evaluate the modular formula above.
For the target instance they use
$F_{82}=61305790721611591,\qquad F_{83}=99194853094755497,\qquad r=89194853094755498.$
One modular multiplication by \(F_{82}\), followed by a parity test and possibly a complement with respect to \(F_{83}\), produces the final label
$56342087360542122.$
The C++ implementation also includes small sanity checks: it finds a Hamiltonian path by brute force on a tiny graph, and for the Fibonacci-sized test case \(n=34\) it compares the entire closed form against a brute-force path. The Java implementation protects the modular product with arbitrary-precision arithmetic, Python relies on native big integers, and C++ uses a wider integer intermediate.
Complexity Analysis
If the target size is \(F_k\), generating Fibonacci numbers up to index \(k\) costs \(O(k)\) time and \(O(k)\) memory. After that one-time setup, answering the question needs only a subtraction, an integer division by \(2\), one modular multiplication, and a parity-dependent branch, so the main computation runs in \(O(1)\) time with \(O(1)\) extra working memory. The brute-force search used for validation is confined to very small checkpoints and is not part of the large-instance algorithm.
Footnotes and References
- Problem page: https://projecteuler.net/problem=669
- Hamiltonian path: Wikipedia — Hamiltonian path
- Fibonacci number: Wikipedia — Fibonacci number
- Modular arithmetic: Wikipedia — Modular arithmetic
- Coprime integers: Wikipedia — Coprime integers