I need to make a program that finds a number with specified collatz sequence length. However, there is always a problem that the program is too slow. For example my current best score that i could get was number with collatz sequence length of 1200 (I need to be able to get number with collatz sequence length of 1800).
I tried a lot of diffrent methods, but the best one so far was trying to recreate collatz number tree.Here is an example from wiki. As I said before i need to be able to get a number with collatz sequence length of 1800 but I cant get more than 1200.
That's my current solution (I know it's complicated but other methods I tried so far were able to get collatz sequence length up to 500 only):
A = int(input())
limit = 1000000000000000000
def runCollaz(ciag):
steps = 0
while ciag != 1:
if (ciag % 2 == 0):
ciag /= 2
else:
ciag *= 3
ciag += 1
steps+=1
return steps
def makeChainLess(number):
if (number % 2 == 0):
return number / 2
else:
return ((number * 3) + 1)
collatzTree = [[1, 1]]
finallAns = "None"
def getAns(collatzTree, what):
awnser = "None"
if (collatzTree[0][0] < limit and collatzTree[0][1] == A):
awnser = collatzTree[0][0]
while (len(collatzTree) > 250):
currentHigh = collatzTree[0][0]
highIndex = 0
index = 0
for x in collatzTree:
if (x[0] > currentHigh):
currentHigh = x[0]
highIndex = index
index += 1
collatzTree.pop(highIndex)
if (collatzTree[0][0] > 4):
if (collatzTree[0][0] - 1) % 3 == 0:
if (collatzTree[0][0] - 1) % 2 != 0:
collatzTree += [[(collatzTree[0][0] - 1) / 3, int(collatzTree[0][1]) + 1]]
collatzTree += [[collatzTree[0][0] * 2, int(collatzTree[0][1]) + 1]]
collatzTree.pop(0)
else:
collatzTree += [[collatzTree[0][0] * 2, int(collatzTree[0][1]) + 1]]
collatzTree.pop(0)
else:
collatzTree += [[collatzTree[0][0] * 2, int(collatzTree[0][1]) + 1]]
collatzTree.pop(0)
if (what == "C"):
return collatzTree
else:
return awnser
while finallAns == "None":
finallAns = getAns(collatzTree, "A")
collatzTree = getAns(collatzTree, "C")
print(int(finallAns))
If anyone could help i would really appricate it.
Here is a simple code that takes only a few minutes to run for 10 million. It just needs more computing power, which is kind of the story on Collatz.
'''
This code finds numbers that have the specified Collatz sequence length
(by brute force)
'''
import time
start = time.time() #start code timer
n = 1 #set low end of range
for number in range (10000000, n-1, -1): #work down from max range
num = number
trial = 0
while number > 1: #set up looping until 1 is reached
if number % 2 == 0: #set up normal Collatz sequence comp.
number = number // 2
else:
number = (number * 3) + 1
trial = trial+1 #update counter for each loop
if number == 1 and trial == 500 or trial == 600: #set target numbers
#print all numbers where specified target occured:
print("Number with sequence "
"length of {0}: {1}".format(trial, num))
if number == n:
print("end of range") #tells user that code has ended
end = time.time()
print("elapsed time: ",end - start)
Related
I've got 2 problems here.
my first problem is that the code shows me only one time a factor even though it's multiple x times by the same factor. I don't know how to add it to the factor list.
Another problem is I'm not sure in print - how the sep works and how can I write "*" only between elements of factor list.
I can't use any import functions here (intertools, maths etc.)
Please help me.
def factorize(n):
prvocisla = []
faktor = []
#prime numbers
for num in range(1, 2000):
if num > 1:
for i in range(2, num):
if (num % i) == 0:
break
else:
prvocisla.append(num)
count = 0
for i in prvocisla:
if n % i == 0:
count += 1
faktor.append(i)
print(n, " =", *faktor , sep=' *', end='\n')
factorize(360)
My result:
360 * = *2 *3 *5
The right result:
360 = 2 * 2 * 2 * 3 * 3 * 5
I try the count function with adding same factor to the list "count times" but it shows me an Error.
The problem is that in your second 'for' loop you evaluate if there is a prime number in your number, but not how many times it is present.
To do this you need to repeat the cycle every time you find a prime number and divide the initial number by the prime number. this way you will get to 1 and get all the factors in the array.
Here the right code:
def factorize(n):
prvocisla = []
faktor = []
#prime numbers
for num in range(1, 2000):
if num > 1:
for i in range(2, num):
if (num % i) == 0:
break
else:
prvocisla.append(num)
count = 0
t = n # <-- a temporary variable which get n value
while t>1:
for i in prvocisla:
if t % i == 0:
count += 1
faktor.append(i)
t = t/i <-- divide t every time you find a factor
break
print(f"{n!s} = {' * '.join(str(k) for k in faktor)}")
factorize(360)
For the print I use the #CreepyRaccoon suggestion.
Problem is from online judge site. I have no idea how my code fails in the tests. I tried possible edge cases but https://www.spoj.com/problems/DIVSUM/, website still gave me error, At first try i went on brute force and loop throught 1 to input number, but efficiency was poor then i search how to develop better solution and found a really good solution to decrase complexity to sqrt(n).
Given a natural number n (1 <= n <= 500000), please output the summation of all its proper divisors.
Definition: A proper divisor of a natural number is the divisor that is strictly less than the number.
e.g. number 20 has 5 proper divisors: 1, 2, 4, 5, 10, and the divisor summation is: 1 + 2 + 4 + 5 + 10 = 22.
import math
def divisorSummation(inp):
divisorsSum = 0
if(inp == 1):
return 0
for i in range(1, int(math.sqrt((inp)))+1):
if(inp % i == 0):
divisorsSum += i
if(i*i != inp and i != 1):
divisorsSum += inp / i
return(int(divisorsSum))
value = int(input())
for i in range(value):
(divisorSummation(int(input())))
Your code works fine. In fact, I submitted your code (with modifications to include output) and it was accepted. Check https://www.spoj.com/status/ ID 30064357 for proof.
import math
def divisorSummation(inp):
if inp == 1:
return 0
divisorsSum = 0
for i in range(1, int(math.sqrt(inp)) + 1):
if inp % i == 0:
divisorsSum += i
if i * i != inp and i != 1:
divisorsSum += inp // i
return divisorsSum
for _ in range(int(input())):
print(divisorSummation(int(input())))
Here is my prime number finding algorithm -- it works great (and very fast) up until the limit is set above 173, then it starts throwing
ValueError: list.remove(x): x not in list
I don't understand why this is when it works absolutely fine up until the limit is 174 or above -- here is my code.
def primefinder(limit):
primes = [2, 3]
for i in range(1, (limit / 6 + 1)):
primes.append(6 * i - 1)
primes.append(6 * i + 1)
for i in primes[:]:
if i > 24:
for x in primes:
if x <= i ** 0.5:
if i % x == 0:
primes.remove(i)
continue
else:
break
if limit % 6 == 0:
primes.remove(primes[-1])
return primes
Here ya go - You don't want to have the print in there, thats just to show what's going on.
def primefinder(limit):
primes = [2, 3]
for i in range(4, limit):
if (prime(i)):
primes.append(i)
print (i)
return primes
def prime(number):
oldnum = number
factor = 1
while number > 1:
factor += 1
if number % factor == 0:
if 1 < factor < oldnum:
return False
number //= factor
return True
primefinder(200000)
I've been trying to write a recursive solution to a program to find a number where first N digits are divisible by N.
As an example: 3816547290, 3 is divisible by 1, 38 is divisible by 2, 381 is divisible by 3 and so on...
My recursive solution works fine while going "into" the recursion, but has issues when the stack unwinds (i.e. I don't specifically know how to backtrack or take steps on the way out
ARR = [0]*10
ARR[0] = 1 #dummy entry
def numSeq(pos, num):
if all(ARR):
print num
return True
if (pos>0) and (num%pos) != 0:
return False
for i in xrange(1,10):
if ARR[i] == 1:
continue
new_num = num*10 + i
if new_num%(pos+1) == 0:
ARR[i] = 1
numSeq(pos+1,new_num)
The problem with this code seems to be that it follows the number generation correctly while going into the recursion...so it correctly generates the number 123654 which is divisible by 6 and follows first N digits being divisible by N, but after it fails to find any further digits from 7-8 or 9 that divide 7, i don't get the next set of steps to "reset" the global ARR and begin from index 2, i.e. try 24xxxx,and eventually get to 3816547290
Thanks in Advance for your help!
EDIT: One condition I'd forgotten to mention is that each digit must be used exactly once (i.e. repetition of digits is disallowed)
2nd EDIT:
I was able to finally apply proper backtracking to solve the problem...this code works as is.
ARR = [0]*10
def numDivisibile(num,pos):
if all(ARR):
print num
return True
for i in xrange(0,10):
if ARR[i] == 1:
continue
new_num = num*10+i
#check for valid case
if new_num%(pos+1) == 0:
ARR[i] = 1
if numDivisibile(new_num, pos+1):
return True
#backtrack
ARR[i] = 0
return False
print numDivisibile(0, 0)
To generate all 10 digits integers where the first n digits are divisible by n for each n from 1 to 10 inclusive:
#!/usr/bin/env python3
def generate_ints_nth_digit_divisible_by_n(n=1, number=0):
number *= 10
if n == 10:
yield number # divisible by 10
else:
for digit in range(not number, 10):
candidate = number + digit
if candidate % n == 0: # divisible by n
yield from generate_ints_nth_digit_divisible_by_n(n + 1, candidate)
print("\n".join(map(str, generate_ints_nth_digit_divisible_by_n())))
Output
1020005640
1020061620
1020068010
...
9876062430
9876069630
9876545640
To get numbers where each digit occurs only once i.e., to find the permutations of the digits that satisfy the divisibility condition:
def divisibility_predicate(number):
digits = str(number)
for n in range(1, len(digits) + 1):
if int(digits[:n]) % n != 0:
return n - 1
return n
def generate_digits_permutation(n=1, number=0, digits=frozenset(range(1, 10))):
# precondition: number has n-1 digits
assert len(set(str(number))) == (n - 1) or (number == 0 and n == 1)
# and the divisibility condition holds for n-1
assert divisibility_predicate(number) == (n - 1) or (number == 0 and n == 1)
number *= 10
if n == 10:
assert not digits and divisibility_predicate(number) == 10
yield number # divisible by 10
else:
for digit in digits:
candidate = number + digit
if candidate % n == 0: # divisible by n
yield from generate_digits_permutation(n + 1, candidate, digits - {digit})
from string import digits
print([n for n in generate_ints_nth_digit_divisible_by_n()
if set(str(n)) == set(digits)])
print(list(generate_digits_permutation()))
Output
[3816547290]
[3816547290]
In your function, you never do return numSeq(...), this seems like causing the issue.
If you want to have a iterative solution, you can check the following:
def getN(number):
strNum = str(number)
for i in range(1, len(strNum)+1):
if int(strNum[:i]) % i != 0:
return i-1
return i
print getN(3816)
print getN(3817)
print getN(38165)
Output:
4
3
5
We can modify your recursive function a little to try different possibilities. Rather than have a global record (ARR) of used positions, each thread of the recursion will have its own hash of used digits:
def numSeq(pos, num, hash):
if pos != 1 and num % (pos - 1) != 0: # number does not pass the test
return
elif pos == 11: # number passed all the tests
print num
elif pos == 5:
numSeq(pos + 1,10 * num + 5,hash) # digit is 5 at position 5
elif pos == 10:
numSeq(pos + 1,10 * num,hash) # digit is 0 at position 10
else:
k = 2 if pos % 2 == 0 else 1 # digit is even at even positions
for i in xrange(k,10,2):
if hash & (1 << i): # digit has already been used, skip it
continue
numSeq(pos + 1,10 * num + i,hash | (1 << i))
numSeq(1,0,0) # 3816547290
I created a function collatz that runs properly. Then based on a list of numbers that I set to be 512 numbers long, should run through the function that many times to add the number of iterations to get to with the loop:
for number in numbers:
collatz(number)
This worked as expected, except that it preempted the iteration within the function. This left me with a list of iterations all reading 0, though the list of numbers populated properly. For reference, the function which I want to copy is:
def collatz(n):
iterations = []
iterations.append(n)
if n == 1 or n < 1:
iterate_num = len(iterations) - 1
all_iterations.append(iterate_num)
elif n % 2 == 0:
even = n / 2
collatz(even)
elif n % 2 != 0:
odd = (3 * n) + 1
collatz(odd)
else:
pass
Is it possible to copy that function a number of times equivalent to the length of the list of numbers to run through each separately?
You should return iterations and extend it with the result of your recursive calls:
def collatz(n):
# Stuff
elif n % 2 == 0:
even = n / 2
iterations.extend(collatz(even))
else:
odd = (3 * n) + 1
iterations.extend(collatz(odd))
return iterations
Another solution would be to pass iterations by reference:
def collatz(n, iterations = None):
if iterations is None:
iterations = []
# Stuff
elif n % 2 == 0:
even = n / 2
collatz(even, iterations)
else:
odd = (3 * n) + 1
collatz(odd, iterations)
Additionally, this construct is unnecessary:
elif n % 2 == 0:
# stuff
elif n % 2 != 0:
# stuff
else:
pass
First off, having an else: than only does pass is unecessary in itself. Additionally, here n % 2 can only either be zero or not zero so the else clause will never be reached.