I have a set of points (represented by complex values), and I need to find the shortest path through these. It looks a bit like the travelling salesman problem, but I can't seem to find (or understand) a solution that isn't in O(n!). I know how to compute short enough solutions in O(n^3), O(n²), but I wanted to know if it was possible to have THE best one. Thank you !
There's the code I use for a "Short Enough Path"
def insert(x,liste,taille):
max_add = 10**9
n = len(liste) -1
for i in range(n):
test = abs(liste[i] -x) + abs(liste[i+1] - x) - taille[i]
if test < max_add:
max_add = test
i_max = i
taille[i_max] = abs(liste[i_max]-x)
taille.insert(i_max+1,abs(liste[i_max+1] - x))
liste.insert(i_max+1,x)
def sort(x,i=0):
taille = [0]
tri = [x[i]]*2
for y in x[:i]+x[i+1:]:
inserer(y,tri,taille)
return tri, taille
def the_best(liste):
n = len(liste)
shortest = 10**9
for i in range(n):
a,b = sort(liste,i)
if sum(b) < shortest:
back = a,b
return back
`
Of course the "the_best" function is in O(n^3) so I usually use the "sort" function only
The list called "taille" is built like this:
taille[i] = abs(liste[i] - liste[i+1])
liste[-1] = liste[0]
From what I understand in your description, this is indeed the TSP problem. It is a well-known NP-hard problem, and as such an efficient algorithm to solve it does not exist (even if it does, we don't know of it yet). It's one of the famous open problems in Computer Science.
Indeed, do give it a try to solve it, but do not hold your breath :)
General reading: https://en.wikipedia.org/wiki/Travelling_salesman_problem
You may also want to give a quick read to: https://en.wikipedia.org/wiki/P_versus_NP_problem
Related
I have been reading the book "Automate the Boring Stuff with Python" and trying to learn Python on my own, I decided to practice what I've learned in chapter one and got a little bit confused by this code and why it doesn't work.
Been sitting and trying to figure it out but still didn't make it.
I've tried to switch the given values of the function and other stuff as well but if I am being honest I don't really know what I am doing I will be very glad if someone explains causes the problem and how to fix it, here's the code :
Mine = {'Bronze': 10,'Iron': 40,'Gold': 2,'Diamonds':2}
def ShowMine(cave):
for k, v in cave.items():
Total_Res = 0
print("There is : " + str(k))
print("And there is : " + str(v) + " of it")
Total_Res += int(v)
print("total ores in the cave : " + str(Total_Res))
def AddOre(cave, ore):
for k,v in cave.items():
cave += ore.values()
Mine1 = {'Bronzze': 10,'Iron': 0,'Gold': 2,'Diamonds':4}
ShowMine(Mine)
AddOre(Mine,Mine1)
ShowMine(Mine)
I expect the code to output the added values from Mine1 to the original Mine created at the start of the program.
The two arguments cave and ore of the function AddOre are both dictionaries. The function then iterates over the items of the first arguments and in each iteration tries to add the return value of ore.values(), which is a list, to the dictionary cave. This doesn't work and I'm not sure what the result of that operation is even supposed to be.
What you want to do, I'm guessing, is to add the values of the second argument to the values of the first argument identifying them by their keys. This can be done by this code:
def AddOre(cave, ore):
for k, _ in cave.items():
if k in ore:
cave[k] += ore[k]
for k, v in ore.items():
if k not in cave:
cave[k] = v
The first loop adds the values of the ores that already exist in the cave and the second loop adds all the new ores. There might be a simpler way to do the same thing with native addition operations of list and dictionary types, but I can't think of any right now.
For educational purposes, I am trying to build an efficient algorithm to find the Least Common Multiple. I already have a quadratic and slow implementation for that. I am trying to build a new one. My new implementation uses a math property involving the Greatest Common Divisor (GCD) and the Least Common Multiple (LCM).
Basically: For any two positive integers a and b,
LCM(a, b) * GCD(a, b) = a * b
I am using Python 3 for that.
I have a very efficient implementation for GCD (it uses another math property, but it is pointless to talk about that):
def euclidean_gcd(a,b):
if b == 0:
return a
else:
a_prime = a%b
return euclidean_gcd(b,a_prime)
My implementation for LCM is:
def lcm_fast(a,b):
return (int((a*b)/(euclidean_gcd(a,b))))
However, when I call:
lcm_fast(1023473145,226553150)
I get as an output:
46374212988031352
The correct answer would be a close number:
46374212988031350
I am a beginner (second year on the Applied Math major), why is this happening?
I am not sure if I could grasp the concept of integer overflow, but, according to my understanding above a little research I did, there is no integer overflow in Python.
I did stress testing and tried to find this mistake in a easier to understand case. However, the problem seems to happen only with really big numbers. Bellow you can check my stress testing for that:
import random
#defina a fronteira máxima dos testes randômicos
print ("insira um número para ser o final do intervalo de testes aleatórios")
bound_right = int(input())
#versão lenta, ou naive
def check_elem_in_list(list_1,list_2):
for element in list_1:
if element in list_2:
return element
else:
return False
#nested loops, vai ter comportamento quadrático
def lcm_slow(num_1,num_2):
list_of_num_1_prod = []
list_of_num_2_prod = []
max_nums = max(num_1,num_2)
end_range = max_nums +1
for i in range(1, end_range):
list_of_num_1_prod.append(i*num_1)
list_of_num_2_prod.append(i*num_2)
if check_elem_in_list(list_of_num_1_prod,list_of_num_2_prod) != False:
return (check_elem_in_list(list_of_num_1_prod,list_of_num_2_prod))
def euclidean_gcd(a,b):
if b == 0:
return a
else:
a_prime = a%b
return euclidean_gcd(b,a_prime)
def lcm_fast(a,b):
return (int((a*b)/(euclidean_gcd(a,b))))
# está dando pau com os inputs 1023473145, 226553150
# vou fazer stress testing
#primeiro, fazer função para gerar testes
a_in = random.randint(1,bound_right)
b_in = random.randint(1,bound_right)
while (lcm_slow(a_in,b_in)==lcm_fast(a_in,b_in)):
a_in = random.randint(1,bound_right)
b_in = random.randint(1,bound_right)
print (a_in,b_in,"OK",lcm_fast(a_in,b_in),lcm_slow(a_in,b_in))
if (lcm_slow(a_in,b_in)!=lcm_fast(a_in,b_in)):
print (a_in, b_in,"OPS",lcm_fast(a_in,b_in),lcm_slow(a_in,b_in))
break
#
EDITED AFTER SOME COMMENTS/ANSWERS TO THE ORIGINAL PROBLEM
Inside this problem, a new problem arrives.
I am building this for a platform. My solution is right. After the comment from Blender. I did that (which was my original solution):
def lcm_fast(a,b):
a = ((a*b)/(euclidean_gcd(a,b)))
return a
The problem is that I receive this message failing on the platform's test cases:
Failed case #1/42: Cannot check answer. Perhaps output format is wrong.
Input: 18 35 Your output: 630.0 Correct output: 630 (Time used: 0.01/5.00, memory used: 9613312/536870912.)
That's funny. If I avoid the approximation with int(), the code is right for big numbers. However, without the conversion from float to int, I am unable to provide the answer on the desired format.
You're converting the result of your division back into an integer with int() because "regular" integer division results in a float. CPython's floats have a fixed precision, so your conversion back and forth will result in lost information for sufficiently large numbers.
Avoid losing precision and perform floor division with //, which returns an integer:
def lcm_fast(a,b):
return (a * b) // euclidean_gcd(a,b)
In python 3, standard division (/) operations will automatically promote to float, while integer division (//) will always return an int.
Thus, python can handle arbitrarily large ints, at some point your data is being treated as a float rather than an int, subjecting it to floating point precision error.
(I see someone else also typed up a similar answer while I was writing this up and feel obligated to make note of this before being bashed to death for copying someone else's answer.)
I need to reach 1,000,000 and for some reason it doesn't give me the output for 1,000,000, I don't know what i am doing wrong. Every time i put a small number like 500 it would give me the correct output but as soon as i put 999,999 or 1,000,000 it just doesn't give out any output and when i do a keyboard interruption it says it stopped at break but I need that break in order for the values to only repeat once.
bachslst=[]
primeslst=[]
q=[]
newlst=[]
z=[]
def goldbach(limit):
primes = dict()
for i in range(2, limit+1):
primes[i] = True
for i in primes:
factors = range(i, limit+1, i)
for f in factors[1:]:
primes[f] = False
for i in primes:
if primes[i]==True:
z.append(i)
for num in range(4,limit+1,2):
for k in range(len(z)):
for j in z:
if (k + j ) == num :
x=(str(k),str(j))
q.append(x)
newlst.append([x,[num]])
break
bachslst.append(num)
print(bachslst,'\n')
return newlst
The break that is referred to is not the break in the code, it is the break caused by the keyboard interrupt.
If you want to get your result in less than 1.5 hours, try to reduce the amount of computing that you are doing. There are many implementations for testing the Goldbach Conjecture if you do a search. Some are in other languages, but you can still use them to influence your algorithm.
I have not looked at it, but here is another implementation in Python: https://codereview.stackexchange.com/questions/99161/function-to-find-two-prime-numbers-that-sum-up-to-a-given-even-number
I'm trying to solve a math problem but I would like to make some informatic tests before to understand what happend (and maybe find the solution with my program), my problem is :
Consider the list consisting of the first n natural numbers without zero, ie from 1 to n.
We define the transformation "moving average" on the list of n elements by adding the average of all the terms at the end of the list and eliminating the first term at the beginning of the list.
For example, if n = 4, we have: (1,2,3,4) -> (2,3,4,2.5)
By iterating this process many times, one can observe a phenomenon of standardization and that all elements of the list tend to a common value when the number of iterations tends to + infinity.
It asks for the value of n for this limit is 254859658745.
Well, i'm trying to program the function "moving average" like this :
def moving_average(liste,t):
k=0
S=0
m=0
c=0
n=len(liste)
while c<t:
while k<n:
S+=int(liste[k])
k+=1
m=S/n
liste.pop(0)
liste.append(m)
c+=1
return m
My program works but don't answer what I want, if I take liste=[1,2,3] (for example) for all t>1 the answer is always the same... but I don't understand why.
Can you help me please ?
In the interests of helping you move forwards, here is the first part of an answer. The way to debug this is like this:
def moving_average(liste,t):
k=0
S=0
m=0
c=0
n=len(liste)
while c<t:
print("At c: ", c)
k=0
while k<n:
print(" At k: ", k)
S+=int(liste[k])
k+=1
m=S/n
print(" .. new S", S)
print(" .. new k", k)
print(" .. new m", m)
liste.pop(0)
liste.append(m)
print(" liste: ", liste)
c+=1
return m
test_list = [1,2,3]
test_t = 4
print("Result:", moving_average(test_list, test_t))
Then look at each result until you find one that isn't what you expect
Since you know better than I do what you expect at each step, you might find the underlying issue quicker than I can by doing this :)
Update:
One "obvious" reason why it's not working is because you're not resetting k each time around the c loop.
If you look at the output before fixing, you will see that the "at K" messages only come out once, the first time through.
I've updated the code above to fix this, and I think it does something like you are expecting. I'm not sure why you are taking taking the int() of liste[k], but that is a separate issue.
What I am trying to do is use a while loop to create a square out of asterixs, the code below will print the square filled in, but what I want it to do is print the square unfilled
a='square'
b='unfilled'
c=4
num=0
asterix='*'
while a=='square' and b=='unfilled' and int(num)<int(c):
num+=1
print(asterix*int(c))
What the code does:
****
****
****
****
What I want the code to do:
****
* *
* *
****
Any help would be much appreciated
n = 4
s = "*"
for i in range(0,n,1):
if i == 0 or i == n-1:
print(s*n)
else:
print(s+(" "*(n-2))+s)
This should do what you want to. You don't have to convert everything correct.
I know this was answered a long time ago, but I am going through some of my earlier class exercises too and trying to use some of the new things I have learned along the way.
This reminds me a lot of one of my exercises and I eventually answered it similar to the answer above. Since then I have discovered a nice way to write this using a generator:
n = 4
table = ("* *" if i not in [0, n] else '****' for i in range(n+1))
for row in table: print(row)
You would probably want to generalise this too so that it worked for a variable size, n.