Pythagorean triple with python - python

I want to get a number 'n' and produce Pythagorean triple that total of them is equal with 'n'.
for example for n=12 my output is 3, 4, 5 (12 = 3 + 4 + 5).
I write below code but it take a lot of time for big numbers. please help me to improve it.
a = int(input())
done = False
for i in range(int(a/4)+1,2,-1):
if done:
break
for j in range(i+1,int(a/2)+1):
k = a-(i+j)
if k <= j:
break
if i**2 + j**2 == k**2:
print(i,j,k)
done = True
break
if done == False:
print('Impossible')

This code may help you
limits = int(input())
c, m = 0, 2
# Limiting c would limit
# all a, b and c
while c < limits :
# Now loop on n from 1 to m-1
for n in range(1, m) :
a = m * m - n * n
b = 2 * m * n
c = m * m + n * n
# if c is greater than
# limit then break it
if c > limits :
break
if a+b+c == limits:
print(a, b, c)
m = m + 1
>> 12
>> 3 4 5

I've used the joblib module to parallelize your code, though I haven't tested if there is a speedup for very large n; let me know:
from joblib import Parallel, delayed
done = False
def triple(a):
global done
for i in range(int(a/4)+1,2,-1):
if done:
break
for j in range(i+1,int(a/2)+1):
k = a-(i+j)
if k <= j:
break
if i**2 + j**2 == k**2:
print(i,j,k)
done = True
break
if done == False:
print('Impossible')
if __name__ == '__main__':
a = int(input("n:"))
Parallel(n_jobs=-1, backend="threading")(map(delayed(triple), [a]))

To generate a Pythagorean triplet of a given sum, you can run two loops, where the first loop runs from i = 1 to n/3, the second loop runs from j = i+1 to n/2. In second loop, we check if (n – i – j) is equal to i * i + j * j.
n = int(input()
for i in range(1, int(n / 3) + 1):
for j in range(i + 1, int(n / 2) + 1):
k = n - i - j
if (i * i + j * j == k * k):
print(i, j, k)

Related

Improving the runinng time of a numerical algorithm by parallel computation, using gmpy2 module of Python

I'm working on a numerical algorithm as follows.
import timeit
import gmpy2
import math
A = gmpy2.mpz(1000007777)
# Input a positive integer to factor.
# Put it inside the parentheses as "A = gmpy2.mpz(....)"
def factor(A):
B = gmpy2.mpz(math.sqrt(2 * A + 0.25) - 1)
D = gmpy2.mpz(A - (B * B + B) / 2)
while (D > 0):
B += 1
D = gmpy2.mpz(A - (B * B + B) / 2)
n = gmpy2.mpz(0)
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
n += 1
D += n
if B > A:
return output(0, 0, 0)
else:
print(f"[B={B}, n={n}]")
if (B - n) % 2 == 0:
E = gmpy2.mpz((B - n) / 2)
F = gmpy2.mpz(B + n + 1)
else:
E = gmpy2.mpz(B - n)
F = gmpy2.mpz((B + n + 1) / 2)
return output(A, E, F)
def output(A, E, F):
if A == 0:
print(f"Initial Value Error: Reset the B value")
else:
if A % E != 0 or A % F != 0 or A != E * F:
print(f"[Error Occurred] {A} != {E} * {F}")
else:
print(f"{A} = {E} * {F}")
return 0
if __name__ == '__main__':
if A >= 2:
timer_start = timeit.default_timer()
factor(A)
timer_stop = timeit.default_timer()
running_time = round(timer_stop - timer_start, 6)
print("running time: ", running_time, " seconds")
else:
print("undefined for A<2")
(Note that the output of B and n comes out as [B=21739322, n=21739276] with our argument in the example code)
The task of this code aims to reach 0 by adding and subtracting integers. The D value shall oscillate between 0 until it reaches 0. I wanted to improve the running time of this task by parallel computation, using multiprocessing module of Python.
import timeit
import gmpy2
import math
import multiprocessing
A = gmpy2.mpz(1000007777)
# Input a positive integer to factor.
# Put it inside the parentheses as "A = gmpy2.mpz(....)"
k = 4
# Input the number of cores to be used as "k=..."
# [!!Caveat!!] Don't use too much number of cores which exceeds the
# availability of CPU resources of your personal computer environment.
# It can damage the CPU !!!
def factor(n):
if A < 2:
print("undefined for A<2")
else:
B = gmpy2.mpz(math.sqrt(2 * A + 0.25) - 1)
D = gmpy2.mpz(A - (B * B + B) / 2)
while (D > 0):
B += 1
D = gmpy2.mpz(A - (B * B + B) / 2)
D += gmpy2.mpz(n * (n + 1) / 2)
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
D += k * n + (k * (k + 1)) / 2
n += k
if B > A:
return output(0, 0, 0)
else:
if (B - n) % 2 == 0:
E = gmpy2.mpz((B - n) / 2)
F = gmpy2.mpz(B + n + 1)
else:
E = gmpy2.mpz(B - n)
F = gmpy2.mpz((B + n + 1) / 2)
return output(A, E, F)
def output(A, E, F):
timer_stop = timeit.default_timer()
running_time = round(timer_stop - timer_start, 6)
if A == 0:
print(f"Initial Value Error: Reset the B or k value \n")
else:
if A % E != 0 or A % F != 0 or A != E * F:
print(f"[Error Occurred] {A} != {E} * {F} \n")
else:
print(f"[running time: {running_time} seconds] {A} = {E} * {F} \n")
return 0
if __name__ == '__main__':
n = []
timer_start = timeit.default_timer()
with multiprocessing.Pool(processes=k) as pool:
for x in range(0, k):
y = gmpy2.mpz(x)
n.append(y)
results = pool.map(factor, n)
The idea behind this is that, executing some addition of integers until meeting its target value, which is 0 in our code, shall be done faster if the added size of integers becomes bigger. For example, it is quite obvious that adding integers as 4+4+4... is faster to reach 100 than adding integers as 1+1+1...
However, my numerical experiments have shown that the latter code of multiprocessing module is nowhere faster than the previous code of single-core.
But, noticing that the value n=21739276 of which we mentioned above is divisible by 4, I've tried the modification of single-core version code as follows
import timeit
import gmpy2
import math
A = gmpy2.mpz(1000007777)
# Input a positive integer to factor.
# Put it inside the parentheses as "A = gmpy2.mpz(....)"
def factor(A):
B = gmpy2.mpz(math.sqrt(2 * A + 0.25) - 1)
D = gmpy2.mpz(A - (B * B + B) / 2)
while (D > 0):
B += 1
D = gmpy2.mpz(A - (B * B + B) / 2)
n = gmpy2.mpz(0)
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
D += 4*n+10
n += 4
if B > A:
return output(0, 0, 0)
else:
print(f"[B={B}, n={n}]")
if (B - n) % 2 == 0:
E = gmpy2.mpz((B - n) / 2)
F = gmpy2.mpz(B + n + 1)
else:
E = gmpy2.mpz(B - n)
F = gmpy2.mpz((B + n + 1) / 2)
return output(A, E, F)
def output(A, E, F):
if A == 0:
print(f"Initial Value Error: Reset the B value")
else:
if A % E != 0 or A % F != 0 or A != E * F:
print(f"[Error Occurred] {A} != {E} * {F}")
else:
print(f"{A} = {E} * {F}")
return 0
if __name__ == '__main__':
if A >= 2:
timer_start = timeit.default_timer()
factor(A)
timer_stop = timeit.default_timer()
running_time = round(timer_stop - timer_start, 6)
print("running time: ", running_time, " seconds")
else:
print("undefined for A<2")
In my computer, this made the running time to be decreased as around 3 seconds from about 4 seconds. So I concluded that the reason for the multiprocessing version code being slower is due to this part
else:
D += k * n + (k * (k + 1)) / 2
n += k
where the code is constantly interpreting what the argument is and translating it as an actual integer.
To avoid this, the easiest way to do is making a several code, when doing parallel computation on 4 cores, as follows.
else:
D += n + 1
n += 1
else:
D += 2*n + 3
n += 2
else:
D += 3*n + 6
n += 3
else:
D += 4*n + 10
n += 4
Among them, only the "n += 3" one will not give a desired output since it is not divisible by 4. (Recall that 4 is a divisor of n=21739276 from our original code)
If there are only 4 cases to test, then you can just make 4 copies of similar code by your hand.
However, let's think about this code
import timeit
import gmpy2
import math
A = gmpy2.mpz(1000007777)
# Input a positive integer to factor.
# Put it inside the parentheses as "A = gmpy2.mpz(....)"
def factor(A):
B = gmpy2.mpz(math.sqrt(2 * A + 0.25) - 1)
D = gmpy2.mpz(A - (B * B + B) / 2)
while (D > 0):
B += 1
D = gmpy2.mpz(A - (B * B + B) / 2)
n = gmpy2.mpz(0)
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
D += 11299*n+63839350
n += 11299
if B > A:
return output(0, 0, 0)
else:
print(f"[B={B}, n={n}]")
if (B - n) % 2 == 0:
E = gmpy2.mpz((B - n) / 2)
F = gmpy2.mpz(B + n + 1)
else:
E = gmpy2.mpz(B - n)
F = gmpy2.mpz((B + n + 1) / 2)
return output(A, E, F)
def output(A, E, F):
if A == 0:
print(f"Initial Value Error: Reset the B value")
else:
if A % E != 0 or A % F != 0 or A != E * F:
print(f"[Error Occurred] {A} != {E} * {F}")
else:
print(f"{A} = {E} * {F}")
return 0
if __name__ == '__main__':
if A >= 2:
timer_start = timeit.default_timer()
factor(A)
timer_stop = timeit.default_timer()
running_time = round(timer_stop - timer_start, 6)
print("running time: ", running_time, " seconds")
else:
print("undefined for A<2")
Note that 11299 is a divisor of n=21739276. Indeed, this has decreased the running time of the code from around 2 seconds from 4 seconds.
If we do the same job with subtract part
if (D > 0):
B += 1
D -= B
I'm sure the code shall be faster but I haven't tried this yet.
So, why do we need to do this? That is, why do we need to make multiple version of similar codes to do a task of this algorithm, instead of directly replacing the arguments with the divisor of n?
It is because, we don't know the B and n value before we try it.
(If you find a method to know them don't tell me, just publish it on some decent journal)
Therefore, unless we figure out any pattern of B and n values to be identified, I believe the best method at current stage is to make multiple copies of similar code to be executed.
Here is the organized question,
Is there any way to replace the 'actual lines' inside a code by following the number of cores to be used?
For example, if there is a desired answer for the question, when there is a original code which include some lines of code as follows,
else:
D += n + 1
n += 1
and applying the method of desired answer shall result in copying the following codes
else:
D += 2*n + 3
n += 2
else:
D += 3*n + 6
n += 3
else:
D += 4*n + 10
n += 4
which do the same task, but only those lines of code have been replaced. If the number of code has been increased to 6, then we will have two more codes to be added that will concurrently executed for doing the task.
else:
D += 5*n + 15
n += 5
else:
D += 6*n + 21
n += 6
To repeat, the 'actual lines' of the code shall be replaced with another 'actual lines' since the following code
else:
D += k * n + (k * (k + 1)) / 2
n += k
is not that helpful for doing the exhaustive task, because of its job of interpreting what the actual argument of k is.
I've tried to be as specific as possible to describe my problem. If you need more elaboration please let me have a chance to elaborate the problem via comments and edits. Thank you.
What I've tried
I've tried to do the similar task at Java. Since Java is well known for OOP, and I thought OOP might be a promising way to solve this problem. However, the problem that Java has, it is not designed for arithmetic. I've tried the BigInteger library but it was extremely slow in my numerical test, even more than Python.
The other possible method could be doing some Scanf job by one's hand for the whole number of the sequence of code I'm going to use to. However, even assuming this method works, if the number of cores to be used increase as thousands then the method would not be considered as the best solution to this.
We've shown that
else:
D += 11299*n+63839350
n += 11299
this code works faster than the previous codes. However for a bigger argument of A, we might need more than thousands, maybe millions of multi-cores, to do the task efficiently.
So I have concluded this method is not the best shot that we can try, leaving aside whether it actually works.
Edit
I wanted to engage on discussion as much as I can. However, because of some unfriendly behavior at the comments, I may refrain myself from doing that. (Really appreciate the answer though)
This could be my last edit in this post. I just wanted to point out, the fact that 11299 is a divisor of n=21739276 doesn't mean that we can't try more than that.
Note that n = 21739276 = 19276 (mod 30000). Then, by replacing that part of the code as follows
n = gmpy2.mpz(19276)
D += gmpy2.mpz(n * (n + 1) / 2)
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
D += 30000*n+450015000
n += 30000
I could reduce the running time from around 2.4seconds to 2.1seconds. I expect the running time can be reduced more if I manipulate this subtraction part,
if (D > 0):
B += 1
D -= B
but I haven't tried yet. All of these elements were the motivation behind that I thought I needed to know how to do the effective parallel computation. As I said, I may not engage on further discussion unless definitely required. If you are interested, you may feel free to test and modify this code without noticing me.
a needlessly long question, but this is python ... you can generate code at runtime if you write the function as a string, and replace the parts you need with numbers from arguments, you can exec the code exactly as you want, but this is not pythonic or fastest.
if your "hot loop" is limited by calculating things that can be known beforehand then it's best to just calculate them before the loop.
k_local = k # magic trick, bind the global k to a local variable k_local to make lookup faster
second_term = (k_local * (k_local + 1)) / 2
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
D += k_local * n + second_term
n += k_local
this has the EXACT same performance as
else:
D += 11299*n+63839350
n += 11299
one thing i can recommend, is to make all variables local, (make k an argument), and use cython to compile your functions to C, this way the compiler overhead is partially removed, and if you really want better performance you can use gmpy's cython "bindings" to manipulate it on C level and remove the interpreter overhead entirely (not the ABI overhead though)
if you really want to go one step further, you can rewrite this in C++ and get more performance, as gmpy is originally a C package, and you will be removing the ABI overhead, do this if you really want to squeeze the last drop of performance out of it, as your "hot loop" is probably too hot for python's virtual machine, that's trying to simulate a computer inside a computer (same to be said for java VM), rewriting this in C++ can be as much as 50 times faster than your current implementation, but the gap can be made as small as only 5 times if you use the previous suggestions.

Sum of 1+3+5...+n until the sum exceeds 100

Then the sum and the last added number and the number of numbers added must be printed.
I am currently stuck, I managed to get the sum part working. The last added number output is printed "23" but should be "21". And lastly, how can I print the number of numbers added?
Output goal: 121, 21, 11
Here is my code:
n = int()
sum = 0
k = 1
while sum <= 100:
if k%2==1:
sum = sum + k
k = k + 2
print('Sum is:', sum)
print("last number:", k)
Edit: Would like to thank everyone for their help and answers!
Note, that (you can prove it by induction)
1 + 3 + 5 + ... + 2 * n - 1 == n**2
<----- n items ----->
So far so good in order to get n all you have to do is to compute square root:
n = sqrt(sum)
in case of 100 we can find n when sum reach 100 as
n = sqrt(100) == 10
So when n == 10 then sum == 100, when n = 11 (last item is 2 * n - 1 == 2 * 11 - 1 == 21) the sum exceeds 100: it will be
n*n == 11 ** 2 == 121
In general case
n = floor(sqrt(sum)) + 1
Code:
def solve(s):
n = round(s ** 0.5 - 0.5) + 1;
print ('Number of numbers added: ', n);
print ('Last number: ', 2 * n - 1)
print ('Sum of numbers: ', n * n)
solve(100)
We have no need in loops here and can have O(1) time and space complexity solution (please, fiddle)
More demos:
test : count : last : sum
-------------------------
99 : 10 : 19 : 100
100 : 11 : 21 : 121
101 : 11 : 21 : 121
Change your while loop so that you test and break before the top:
k=1
acc=0
while True:
if acc+k>100:
break
else:
acc+=k
k+=2
>>> k
21
>>> acc
100
And if you want the accumulator to be 121 just add k before you break:
k=1
acc=0
while True:
if acc+k>100:
acc+=k
break
else:
acc+=k
k+=2
If you have the curiosity to try a few partial sums, you immediately recognize the sequence of perfect squares. Hence, there are 11 terms and the last number is 21.
print(121, 21, 11)
More seriously:
i, s= 1, 1
while s <= 100:
i+= 2
s+= i
print(s, i, (i + 1) // 2)
Instead of
k = k + 2
say
if (sum <= 100):
k = k +2
...because that is, after all, the circumstance under which you want to add 2.
To also count the numbers, have another counter, perhasp howManyNumbers, which starts and 0 and you add 1 every time you add a number.
Just Simply Change you code to,
n = int()
sum = 0
k = 1
cnt = 0
while sum <= 100:
if k%2==1:
sum = sum + k
k = k + 2
cnt+=1
print('Sum is:', sum)
print("last number:", k-2)
print('Number of Numbers Added:', cnt)
Here, is the reason,
the counter should be starting from 0 and the answer of the last printed number should be k-2 because when the sum exceeds 100 it'll also increment the value of k by 2 and after that the loop will be falls in false condition.
You can even solve it for the general case:
def sum_n(n, k=3, s =1):
if s + k > n:
print('Sum is', s + k)
print('Last number', k)
return
sum_n(n, k + 2, s + k)
sum_n(int(input()))
You can do the following:
from itertools import count
total = 0
for i, num in enumerate(count(1, step=2)):
total += num
if total > 100:
break
print('Sum is:', total)
print("last number:", 2*i + 1)
To avoid the update on k, you can also use the follwoing idiom
while True:
total += k # do not shadow built-in sum
if total > 100:
break
Or in Python >= 3.8:
while (total := total + k) <= 100:
k += 2
Based on your code, this would achieve your goal:
n = 0
summed = 0
k = 1
while summed <= 100:
n += 1
summed = summed + k
if summed <= 100:
k = k + 2
print(f"Sum is: {summed}")
print(f"Last number: {k}")
print(f"Loop count: {n}")
This will solve your problem without changing your code too much:
n = int()
counter_sum = 0
counter = 0
k = 1
while counter_sum <= 100:
k+= 2
counter_sum =counter_sum+ k
counter+=1
print('Sum is:', counter_sum)
print("last number:", k)
print("number of numbers added:", counter)
You don't need a loop for this. The sum of 1...n with step size k is given by
s = ((n - 1) / k + 1) * (n + 1) / k
You can simplify this into a standard quadratic
s = (n**2 - k * n + k - 1) / k**2
To find integer solution for s >= x, solve s = x and take the ceiling of the result. Apply the quadratic formula to
n**2 - k * n + k - 1 = k**2 * x
The result is
n = 0.5 * (k + sqrt(k**2 - 4 * (k - k**2 * x - 1)))
For k = 2, x = 100 you get:
>>> from math import ceil, sqrt
>>> k = 2
>>> x = 100
>>> n = 0.5 * (k + sqrt(k**2 - 4 * (k - k**2 * x - 1)))
>>> ceil(n)
21
The only complication arises when you get n == ceil(n), since you actually want s > x. In that case, you can test:
c = ceil(n)
if n == c:
c += 1

Find how many combinations of integers possible to reach the result

I'm a bit stuck on a python problem.
I'm suppose to write a function that takes a positive integer n and returns the number of different operations that can sum to n (2<n<201) with decreasing and unique elements.
To give an example:
If n = 3 then f(n) = 1 (Because the only possible solution is 2+1).
If n = 5 then f(n) = 2 (because the possible solutions are 4+1 & 3+2).
If n = 10 then f(n) = 9 (Because the possible solutions are (9+1) & (8+2) & (7+3) & (7+2+1) & (6+4) & (6+3+1) & (5+4+1) & (5+3+2) & (4+3+2+1)).
For the code I started like that:
def solution(n):
nb = list(range(1,n))
l = 2
summ = 0
itt = 0
for index in range(len(nb)):
x = nb[-(index+1)]
if x > 3:
for index2 in range(x-1):
y = nb[index2]
#print(str(x) + ' + ' + str(y))
if (x + y) == n:
itt = itt + 1
for index3 in range(y-1):
z = nb[index3]
if (x + y + z) == n:
itt = itt + 1
for index4 in range(z-1):
w = nb[index4]
if (x + y + z + w) == n:
itt = itt + 1
return itt
It works when n is small but when you start to be around n=100, it's super slow and I will need to add more for loop which will worsen the situation...
Do you have an idea on how I could solve this issue? Is there an obvious solution I missed?
This problem is called integer partition into distinct parts. OEIS sequence (values are off by 1 because you don't need n=>n case )
I already have code for partition into k distinct parts, so modified it a bit to calculate number of partitions into any number of parts:
import functools
#functools.lru_cache(20000)
def diffparts(n, k, last):
result = 0
if n == 0 and k == 0:
result = 1
if n == 0 or k == 0:
return result
for i in range(last + 1, n // k + 1):
result += diffparts(n - i, k - 1, i)
return result
def dparts(n):
res = 0
k = 2
while k * (k + 1) <= 2 * n:
res += diffparts(n, k, 0)
k += 1
return res
print(dparts(201))

find total data in N*N matrix

a matrix consists of N × N blocks .the block number is equal to the sum of the row number and the column number. each block consists of data, and data is equal to difference of sum of even and odd digits of the block number . calculate total data of n*n blocks
i/o format
lets n = 4
so
matrix will be
2 3 4 5
3 4 5 6
4 5 6 7
5 6 7 8
so total data = 2+3+4+5+3+4+5+6+4+5+6+7+5+6+7+8=80
if number of block is 4256 in any case then data in it will be abs(diff(sum(even digits)- sum(odd digits))) which is abs((4+2+6)-(5))= 7
my naive attempt
n = int(raw_input())
sum1=0
sum2=0
for i in range(1,n+1):
for j in range(1,n+1):
sum1 = i+j
diffsum = diff(sum1)
sum2 = sum2+diffsum
print sum2
again optimized attempt
def diff(sum1):
sum1 = str(sum1)
m = sum([int(i) for i in sum1 if int(i) % 2 == 0])
f = sum([int(i) for i in sum1 if int(i) % 2 != 0])
return abs(m - f)
n = int(raw_input())
sum1 = 0
k = 1
# t1 = time.time()
p = 2 * n
for i in range(2, n + 2):
diffsum = diff(i)
diffsum1 = diff(p)
sum1 = sum1 + (diffsum * k)
sum1 = sum1 + (diffsum1 * k)
p = p - 1
k = k + 1
sum1 = sum1 - (diff(n + 1) * n)
print sum1
diff is common function in both case. i need more optmization with the following algorithm
Your optimised approach calculates the digit sum only once for each number, so at first sight, there isn't anything to be gained from memoisation.
You can improve the performance of your diff function by merging the two loops into one and use a dictionary to look up whether you add or subtract a digit:
value = dict(zip("0123456789", (0, -1, 2, -3, 4,-5, 6,-7, 8,-9)))
def diff2(s):
s = str(s)
return abs(sum([value[i] for i in s]))
This will require a conversion to string. You can get a bit faster (but not much) by calculating the digits by hand:
dvalue = [0, -1, 2, -3, 4,-5, 6,-7, 8,-9]
def diff(s):
t = 0
while s:
t += dvalue[s % 10]
s //= 10
return abs(t)
Finally, you can make use of the fact that you calculate all digit sums from 2 up to 2·n sequentially. Store the digits of the current number in an array, then implement an odometer-like counter. When you increment that counter, keep track of the odd and even digit sums. In 9 of 10 cases, you just have to adjust the last digit by removing its value from the respective sum and by adding the next digit to the other sum.
Here's a program that does this. The function next increments the counter and keeps the digit sums of even and odd numbers in sums[0] and sums[1]. The main program is basically the same as yours, except that the loop has been split into two: One where k increases and one where it decreases.
even = set(range(0, 10, 2))
def next(num, sums):
o = num[0]
if o in even:
sums[0] -= o
sums[1] += o + 1
else:
sums[0] += o + 1
sums[1] -= o
num[0] += 1
i = 0
while num[i] == 10:
sums[0] -= 10
num[i] = 0
i += 1
o = num[i]
if o in even:
sums[0] -= o
sums[1] += o + 1
else:
sums[0] += o + 1
sums[1] -= o
num[i] += 1
n = int(raw_input())
total = 0
m = len(str(2 * n + 1))
num = [0] * m
num[0] = 2
sums = [2, 0]
k = 1
for i in range(2, n + 2):
total += abs(sums[0] - sums[1]) * k
k += 1
next(num, sums)
k = n
for i in range(n + 2, 2*n + 1):
k -= 1
total += abs(sums[0] - sums[1]) * k
next(num, sums)
print total
I've said above that memoisation isn't useful for this approach. That's not true. You could store the even and odd digit sums of number i and make use of it when calculating the numbers 10 * i to 10 * i + 9. When you call diff in order of increasing i, you will have access to the stored sums of i // 10.
This isn't significantly faster than the odometer approach, but the implementation is clearer at the cost of additional memory. (Preallocated arrays work better than dictionaries for big n. You don't need to reserve space for numbers above (2*n + 11) / 10.)
def diff(s):
d = s % 10
e = ememo[s / 10]
o = omemo[s / 10]
if d in even:
e += d
else:
o += d
if s < smax:
ememo[s] = e
omemo[s] = o
return e, o
n = int(raw_input())
total = 0
even = set(range(0, 10, 2))
smax = (2*n + 11) / 10
omemo = smax * [0]
ememo = smax * [0]
omemo[1] = 1
k = 1
for i in range(2, n + 2):
e, o = diff(i)
total += abs(e - o) * k
k += 1
k = n
for i in range(n + 2, 2*n + 1):
k -= 1
e, o = diff(i)
total += abs(e - o) * k
print total
This could be made even faster if one could find a closed formula for the digit sums, but I think that the absolute function prevents such a solution.

Leaving the for / while loop if certain conditions are met

I wrote a set of codes to calculate a Diophantine equation:
bestSoFar = 0
packages = (6,9,20)
numMc = 0
guess= 0
possibn = []
for n in xrange(1, 150):
for a in xrange(0, (n/ packages[0]) +1):
for b in xrange(0,(n/ packages[1]) +1):
c = (n - packages[0]* a - b * packages[1]) / packages[-1]
numMc = packages[0] *a + packages[1] * b + packages[-1] * c
if numMc == n and n not in possibn:
possibn.append(n)
print possibn
if len(possibn) >6 and possibn [-1] - possibn[-6] == 5:
bestSoFar = n
break
The original problem set is designed by the MIT course. Basically it is to calculate the number of McNuggets that could be bought by arranging the ratio of packages-in-different-size ( McDonald does 6,9,20 McNuggets in a package). Say, 21 McNuggets could be bought by buying two 6-McNuggets and one 9-McNuggets. if the number of McNuggets are possible to be bought in exact quantity of packages, I store them into a list. It is found that if 6 consecutive numbers are also possible to be bought in exact quantity, the remained numbers could also be possible.
From my code the result of bestSoFar=149 while the expected answer is 40. The reason would be that it keeps looping until n reaches 149. I would like to stop right at 40 ( with the break statement). However, it fails and I am seeking the advices for you all. Also, if there is anyway to program the problem faster/easier, I am happy to know and learn it too.
Thank you so much.
Casey
If you are not supposed to use a function, just assign a variable to cause breaks out of the other loops.
bestSoFar = 0
packages = (6,9,20)
numMc = 0
guess= 0
possibn = []
finished = False
for n in xrange(1, 150):
for a in xrange(0, (n/ packages[0]) +1):
for b in xrange(0,(n/ packages[1]) +1):
c = (n - packages[0]* a - b * packages[1]) / packages[-1]
numMc = packages[0] *a + packages[1] * b + packages[-1] * c
if numMc == n and n not in possibn:
possibn.append(n)
# print possibn
if len(possibn) >6 and possibn [-1] - possibn[-6] == 5:
bestSoFar = n
finished = True
break
if finished: break
print bestSoFar
Turn it into a function and return:
from __future__ import print_function
def solve(*packages):
bestSoFar = 0
numMc = 0
guess= 0
possibn = []
for n in xrange(1, 150):
for a in xrange(0, (n / packages[0]) + 1):
for b in xrange(0, (n / packages[1]) + 1):
c = (n - packages[0] * a - b * packages[1]) / packages[-1]
numMc = packages[0] * a + packages[1] * b + packages[-1] * c
if numMc == n and n not in possibn:
possibn.append(n)
print possibn
if len(possibn) > 6 and possibn [-1] - possibn[-6] == 5:
return n
return bestSoFar
x = solve(6, 9, 20)
print(x)
I am not actually clear on what you are expecting. But, what i see is you want to break out of everything. The break which you have given only exits inner loop. Put another break statement outside the inner loop and inside first loop.

Categories