Skip to content

Commit 480e091

Browse files
committed
Euler 86 finally solved within 3 secs
1 parent 6b62f37 commit 480e091

File tree

2 files changed

+92
-74
lines changed

2 files changed

+92
-74
lines changed

euler86_cuboid.py

Lines changed: 92 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,98 @@
11
# euler 86
2-
import math
2+
3+
"""
4+
Damnn this problem taught me a alotttt. Damnnnn OMfucking geeeee Damnnnn nibbazzz! figured it out mother fuckerssssss!!!!
5+
Okay here is the theory behind the problem and how I solved it. I just needed to sit in a place and think properly for a sec...
6+
7+
For any triple P Q R, where P < Q <R; we wanna express P and Q as (a,b,c) such that a<=b<=c
8+
9+
Now, the shortest dist pair will be sqrt((a+b)**2+ c**2) because of our condition. So we don't really have to compute the distance as long
10+
as abc are sorted.
11+
12+
if P & Q are less than the upper limit M:
13+
P can be expressed as: (a+b) and Q can be c
14+
or similarly
15+
P can be expressed as a and Q can be expressed as (b+c)
16+
for P, we can express a total of floor(P/2) unique splits
17+
and for Q we can express a total of floor(Q/2) unique splits
18+
19+
but for Q we have to aware of a condition where, the splits of Q are smaller than P (cuz of a<=b<=c condition)
20+
so we eliminate all pairs for Q where smallest value is greater than P.
21+
22+
For example:
23+
24+
consider the triple (P,Q,R) == (6,8,10)
25+
26+
P can be split into a total of floor(P/2) ways (3 ways):
27+
(1, 5)
28+
(2, 4)
29+
(3, 3)
30+
31+
then pick any pair and it will satisfy the condition of:
32+
(a+b)**2+c**2 = R**2
33+
(1+5)**2+8**2 = 10**2
34+
35+
But for splits of Q, we can see:
36+
(1,7) --> (1,7,6) (a<=b<=c fails here)
37+
(2,6) --> (2,6,6) a<=b<=c
38+
(3,5) --> (3,5,6) a<=b<=c
39+
(4,4) --> (4,4,6) a<=b<=c
40+
41+
So we can't split Q as 1,7 as that will violate the condition.
42+
To count that out it is easy to see that No.of ways to skip = Q-P-1
43+
44+
in this case it is: 8-6-1 = 1
45+
so total ways for Q = floor(Q/2)-(Q-P-1) = (8/2)-(1) = 3
46+
47+
SO total unique pairs that can be generated for (6,8,10) is 3(for P) + 3(forQ) = 6
48+
49+
if Q-P-1 <0 then don't count Q at all
50+
"""
351
import time
4-
import operator as op
5-
from functools import reduce
6-
from itertools import combinations
7-
8-
# a smarter distance func
9-
dist2 = lambda s: math.sqrt(s)
10-
11-
# spider is at start of a
12-
# fly is at the end of c
13-
# square lookup:
14-
square_lookup = {}
15-
familiar_pair = {}
16-
familiar_combinations = {}
17-
seen_results = {}
18-
def shortest_dist2(a, b, c):
19-
if a not in square_lookup:
20-
square_lookup[a] = a**2
21-
if b not in square_lookup:
22-
square_lookup[b] = b**2
23-
if c not in square_lookup:
24-
square_lookup[c] = c**2
25-
base = square_lookup[c]+square_lookup[b]+square_lookup[a]
26-
s1 = base+(2*b*c)
27-
s2 = base+(2*a*c)
28-
s3 = base+(2*a*b)
29-
if s1 not in familiar_pair:
30-
familiar_pair[s1] = dist2(s1)
31-
if s2 not in familiar_pair:
32-
familiar_pair[s2] = dist2(s2)
33-
if s3 not in familiar_pair:
34-
familiar_pair[s3] = dist2(s3)
35-
p1 = familiar_pair[s1]
36-
p2 = familiar_pair[s2]
37-
p3 = familiar_pair[s3]
38-
return min(p1, p2, p3)
39-
40-
def ncr(n, r):
41-
r = min(r, n-r)
42-
numer = reduce(op.mul, range(n, n-r, -1), 1)
43-
denom = reduce(op.mul, range(1, r+1), 1)
44-
return numer // denom
45-
46-
def dim_generator2(M):
47-
for i in range(1, M+1):
48-
for j in range(1, M+1):
49-
yield (i, i, j)
50-
combs = list(combinations([i for i in range(1,M+1)], 3))
51-
for a,b,c in combs:
52-
yield (a, b, c)
52+
def pythagoreanTriplets(limits) :
53+
c, m = 0, 2
54+
while c < limits :
55+
for n in range(1, m) :
56+
a = m * m - n * n
57+
b = 2 * m * n
58+
c = m * m + n * n
59+
if c > limits :
60+
break
61+
yield (a, b, c)
62+
m = m + 1
5363

5464
start = time.time()
55-
seen_dims = {}
56-
total_ints = 0
57-
upper_lim = 1000000
58-
upper_lim = 1000
59-
upper_lim = 500
60-
for a,b,c in dim_generator2(upper_lim):
65+
upper_lim = 1818
66+
67+
def count_combs(A, B, U):
68+
temp = 0
69+
if A<=U and B<=U:
70+
temp+=int(A/2)
71+
ways = B-A-1
72+
if (int(B/2)-ways)>=0:
73+
temp+=(int(B/2)-ways)
74+
if A<=U and B>U and int(B/2) <=U:
75+
ways = B-A-1
76+
if (int(B/2)-ways)>=0:
77+
temp+=(int(B/2)-ways)
78+
if A>U:
79+
temp =0
80+
return temp
81+
82+
is_triples={}
83+
total_count = 0
84+
xs = []
85+
m2=set()
86+
for a, b, c in pythagoreanTriplets(10000):
6187
S = [a,b,c]
6288
S.sort()
63-
dim_set = ','.join(list(map(str,S)))
64-
if dim_set in seen_dims:
65-
continue
66-
seen_dims[dim_set] = True
67-
distance = shortest_dist2(a,b,c)
68-
if distance.is_integer():
69-
total_ints+=1
70-
print(total_ints)
71-
72-
print("finished in: ", time.time()-start)
73-
74-
# val = upper_lim + (upper_lim*(upper_lim-1))+ ncr(upper_lim, 3)
75-
# print(val, upper_lim**3)
76-
# the current loop generates
77-
# 1000000000000000000
78-
# when the total uniques are
79-
# 166667166667000000
80-
89+
for i in range(1,1000):
90+
A,B = i*S[0], i*S[1]
91+
if (A,B) in is_triples:
92+
continue
93+
X = count_combs(A, B, upper_lim)
94+
xs.append(X)
95+
total_count+=X
96+
is_triples[A,B]=True
97+
print(total_count)
98+
print("finished in: ", time.time()-start)

out.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)