An upper bound is
$n = 3361$
Note that
If there are $6$ pairs summing to square numbers such that there are only $4$ numbers used across the pairs then we cannot split these $6$ pairs into $3$ stacks in any way.
Now we can
search for such scenarios by first forming all sets of $3$ pairs that contain $3$ distinct numbers (for example $\{(6, 19), (6, 30), (19, 30)\}$) and then checking for a distinct $4^\text{th}$ number less than the maximum of those that forms a pair with each of the $3$.
Some code:
def squarePairs(n):
for a in range(1, n + 1):
for b in range(a + 1, n + 1):
if ((a + b) ** .5) % 1 == 0:
yield a, b
def squarePairTriples(n):
sPs = list(squarePairs(n))
for ai, a in enumerate(sPs):
for bi, b in enumerate(sPs[ai + 1:]):
if a[0] == b[0]:
c = (a[1], b[1])
elif a[0] == b[1]:
c = (a[1], b[0])
elif a[1] == b[0]:
c = (a[0], b[1])
elif a[1] == b[1]:
c = (a[0], b[0])
else:
continue
if c in sPs[bi + 1:]:
yield a, b, c
def findD(squarePairTriple):
tripleVs = set()
for t in squarePairTriple:
for v in t:
tripleVs.add(v)
for d in range(1, max(tripleVs)):
if d not in tripleVs:
for v in tripleVs:
if ((d + v) ** .5) % 1:
break
else:
return d
Now we can find an upper bound like so:
>>> g = squarePairTriples(5000)
>>> for t in g:
... d = findD(t)
... if d:
... t, d
The first case that this produces is:
(((2, 359), (2, 3362), (359, 3362)), 482)
and:
$2+359=19^2$;
$2+3362=58^2$;
$359+3362=61^2$;
$2+482=22^2$;
$359+482=29^2$; and
$3362+482=62^2$
Edit: This (original route) is not quite right...
For a brute force approach that does not explode as fast as a naive approach we can note that
at the maximal $n+1$ (the first impossible point) there will be $4$ pairs summing to square numbers such that there are only $4$ numbers used across the pairs and $1$ of these will be in all $4$ pairs (thus we cannot split these $4$ pairs into $3$ stacks).
Edit: not right because:
There will never be such a set of four pairs - as one number would have to be in one of the pairs twice.
Furthermore
if we have the square pairs for $n-1$ we can find the square pairs for $n$ by just inspecting the new pairs that may be formed and appending them to the ones for $n-1$.
We may
be able to improve upon this when we are checking for the condition by only inspecting new combinations of $4$ square pairs formed.
but i have not done that yet.
Code so far:
from itertools import combinations
# note: this will return non-square pairs if n gets big, due to the floating point arithmetic
def squarePairs(n, prevKnown=[], prev=0):
res = list(prevKnown)
newCards = [i for i in range(prev + 1, n + 1)]
for a in newCards:
for b in range(1, a):
if ((a + b) ** .5) % 1 == 0:
res.append((b, a))
return res
def findImpossible():
n = 3
sPs = squarePairs(n)
fSPsSet = set()
while 1:
for fSPs in combinations(sPs, 4):
fSPsSet.clear()
for fSP in fSPs:
for i in fSP:
fSPsSet.add(i)
if len(fSPsSet) == 4 and any(sum(1 for fSP in fSPs if i in fSP) == 4 for i in fSPsSet):
return n, fSPs
print("{0} is possible".format(n))
sPs = squarePairs(n + 1, sPs, n)
n += 1
findImpossible
is currently running and has shown that
$3$ to $75$ inclusive are possible.