Where should I modify my breadth first search algo for finding the shortest path between 2 nodes? - python-3.x

I am taking a graph algo course, i am stuck with this problem of finding the shortest path between 2 vertices.
The problem statement : Given an un-directed graph with n vertices and m edges and two vertices u and v, compute the length of the shortest path between u and v. Output the minimum number of edges in a path from u to v, or −1 if there is no path.
My code is passing some test-cases, but few of them are failing, and i can't really see where am i going wrong, so any kind of insight would really be helpful.
def explore(arr, start, end, vis):
vis[start] = 0; q = [start] # queue for storing the node for exploring
while len(q) != 0: # iterates till queue isn't empty
u = q.pop()
for i in arr[u]: # checks for all nodes connected to uth node
if vis[i] == -1: # if the node is unvisited
q.insert(0, i)
vis[i] = vis[u] + 1
elif vis[i] > vis[u] + 1: # if the visited node has shorter path
q.insert(0, i)
vis[i] = vis[u] + 1
return vis[end]
if True:
n, m = map(int, input().split()) # n : vertices, m : edges
arr = {} # stores edges
for i in range(m): # accepts edges as inputs
a, b = map(int, input().split()) # (a,b) >(0,0)
if a-1 in arr.keys():
arr[a-1].append(b-1)
else:
arr[a-1] = [b-1]
if b-1 in arr.keys():
arr[b-1].append(a-1)
else:
arr[b-1] = [a-1]
if m > 0:
start, end = map(int, input().split()) # start : source node, end = dest node
vis = [-1 for i in range(n)] # will store shortest path for each node
print(explore(arr, start-1, end-1, vis))
else:
print(-1)

You have issues with your code due to problems with indexes. You use indexes started from 1 here: q = [start] but later you use indexes started from 0: for i in arr[u] (note, no -1) and so on. I strictly recommend to use indexing from 0 everywhere - it's definitely more readable and helps to avoid possible errors with indexes. Also, you don't really need your elif case if you add new item to the end of q (you insert it to start of q for some reason). Corrected code (warning - indexes in input parameters starts from 0 everywhere!):
def explore(arr, start, end, vis):
vis[start] = 0
q = [start] # queue for storing the node for exploring
while len(q): # iterates till queue isn't empty
u = q.pop()
for i in arr[u]: # checks for all nodes connected to uth node
if vis[i] == -1: # if the node is unvisited
q.append(i)
vis[i] = vis[u] + 1
return vis[end]

Related

OR-TOOLS - how to solve ordered allocation problem?

I have 'n' tables and I have 'm' boxes.
The job is to stack all the boxes on tables.
Question:
what are the different possible combinations?
important note: all the boxes are ordered when put on a table, like stacks. I need to know the rank of each box in the stack.
how to implement that problem with ORTOOL constraint programming / SAT?
what is the best strategy? what variables / constraints?
(I dont expect code, but just advices... unless you are a fast developer :)
Thanks
from ortools.sat.python import cp_model
class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback):
def __init__(self, variables):
cp_model.CpSolverSolutionCallback.__init__(self)
self.__variables = variables
self.__solution_count = 0
def on_solution_callback(self):
self.__solution_count += 1
for v in self.__variables:
print('%s=%i' % (v, self.Value(v)))
print("")
def solution_count(self):
return self.__solution_count
def main():
variables = []
model = cp_model.CpModel()
#################################################
nb_tables = 3
nb_boxes = 4
for box in range(nb_boxes):
box_to_table = model.NewIntVar(0, nb_tables - 1, 'box_'+str(box)+'_to_table')
variables.append(box_to_table)
ranking_variables = []
for box in range(nb_boxes):
rank_of_box_on_its_table = model.NewIntVar(0, nb_boxes - 1, 'rank_of_box_'+str(box)+'_on_its_table')
variables.append(rank_of_box_on_its_table)
ranking_variables.append(rank_of_box_on_its_table)
# the next line is not good because the ranking is global
# and not local to each table. how to manage that?
model.AddAllDifferent(ranking_variables)
#################################################
solver = cp_model.CpSolver()
solution_printer = VarArraySolutionPrinter(variables)
status = solver.SearchForAllSolutions(model, solution_printer)
print('Status = %s' % solver.StatusName(status))
print('Number of solutions found: %i' % solution_printer.solution_count())
main()
And with the boolean version:
#################################################
nb_tables = 3
nb_boxes = 4
for box in range(nb_boxes):
this_box_vars = []
for table in range(nb_tables):
box_in_table = model.NewBoolVar('box_'+str(box)+'_in_table_' + str(table))
variables.append(box_in_table)
this_box_vars.append(box_in_table)
model.Add(sum(this_box_vars) == 1)
ranking_variables = []
for box in range(nb_boxes):
rank_of_box_on_its_table = model.NewIntVar(0, nb_boxes - 1, 'rank_of_box_'+str(box)+'_on_its_table')
variables.append(rank_of_box_on_its_table)
ranking_variables.append(rank_of_box_on_its_table)
# the next line is not good because the ranking is global
# and not local to each table. how to manage that?
model.AddAllDifferent(ranking_variables)
#################################################
Don't use integer variables.
Rule of the thumb:
if you see an AllDifferent constraint, remove it, and replace the integer variable by a list of Boolean variables.
Add Sum(bool_vars) == 1
x[i][j][k] is a Boolean variable indicating that box i is on table j at position k.
y[j][k] indicates if a box in on table j at position k.
each box appears exactly once:
forall i: Sum on j, k box[i][j][k] == 1
each position is occupied by at most one box:
forall j, k: sum on i box[i][k][k] <= 1
if a box is somewhere, it means this somewhere is occupied:
forall i, j, k: box[i][j][k] implies y[j][k]
if a position is occupied, there must be a box at this position:
forall j, k: bool_or([y[j][k].Not(), box[0][j][k], .., box[n - 1][j][k]])
positions must be densely occupied starting from 0 on a table:
forall j, k (except last position): y[j][k].Not() implies y[j][k + 1].Not()
If you want the rank of a box
forall i: rank[i] == sum over j, k box[i][j][k] * k

I can’t find the source of my runtime error. Implemented recursion to solve a problem

I’m trying to answer this problem on code forces. Here is my latest submission (I think others can be found from there).
My method:
Read inputs. The list of lists "mapp" stores the cities that are connected to the city represented by the index of the list i.e. mapp[i-1] represents the cities connected to the i’th city.
I’m using DFS method to solve the problem as per the tutorial for the problem.
When I run the test cases given in the problem the code runs fine and I get correct answers. However, when I submit the problem I always get a runtime error on test 4. I
n = int(input())
def hasChildren(prev, current):
node = mapp[current-1]
travelled = 0.0
l1 = len(node)
if len(node) == 1 and node[0] == prev:
return 0.0
for elem in node:
if elem == prev:
l1 -= 1.0
else:
travelled += (1.0+hasChildren(current, elem))
return travelled/l1
if n == 1:
print("%.6f" % 0.000000)
else:
mapp = [[] for x in range(n)]
for x in range(n-1):
[u,v] = list(map(int, input().split(" ")))
mapp[u-1].append(v)
mapp[v-1].append(u)
length = hasChildren(1,1)
print("%.6f" %length)

How can I take max value from some list but with some conditions?

list1 = [140,232,857,273,405,374,1234,394,1803]
u = 0
b = 4
for i in list1[u:b]
u+= 4
u+= 4
print(max(i))
Now I wanna take the max value from that list but only from list1[0:4] and continue with that.
Now I want to do something like it on this code:
for im in images:
ww, hh = zip(*(im.size for im in images))
www, hhh = im.size
max_h = max(hh)
y_test = []
try:
new_im.paste(im, (x_offset,y))
with open('x.txt', 'a') as file:
file.write(str(x_offset) + "\n")
with open('y.txt', 'a') as file:
file.write(str(y) + "\n")
with open('w.txt', 'a') as file:
file.write(str(www) + "\n")
with open('h.txt', 'a') as file:
file.write(str(hhh) + "\n")
x_offset += im.size[0]
if x_offset > int(q_w) - www:
print(max(hh))
x_offset =0
y += max(hhh)
if hh < y:
y += hhh
if hh > y:
y -= hhh
else:
y += max_h
except:
continue
if x_offset > int(q_w) - www then I want to take the max value of hhh until here.
How can I do that?
Please understand that we apply max( ... ) to a sequence,
rather than to a single scalar value,
e.g. max([6, 7, 8]) rather than max(4).
That first example was unclear.
I think your intent is to run a window of size k=4 over the list
and display local maxima.
A more natural way to express that, without incrementing u inside the loop,
would be:
for i in range(len(list1) - k):
window = list1[i : i + k]
print(i, max(window))
A very similar approach would apply to your second example.
Phrase the for loop in this way, and slice off k elements:
for i, im in enumerate(images):
if i + k < len(images):
window = images[i : i + k]
...
After that you're on your own,
do something useful with window,
as your question was unclear on details of what you want.
You wrote this line within the loop:
ww, hh = zip(*(im.size for im in images))
It computes the same thing each time, so to make things quicker
it belongs outside the loop.
Additionally, it trashes the im iteration variable,
so for the rest of the loop im is a constant value,
it is always the last element of images.
This seems Bad, it's probably not what you wanted.
Similarly, this is a constant
which could be hoisted outside the loop:
max_h = max(hh)
Also, your except: continue is correct,
but except: pass would be the more usual idiom,
expressing the intent to simply ignore the exception.
No statements follow it in the code you posted,
so both would work out the same.
Understand that continue would skip to top-of-loop,
skipping the following statements if there were any.

Extract list from all_simple_paths and their lengths in python

I have a long list of sources and targets that form a graph as follows:
id_a = [...] #source nodes
id_b = [...] #target nodes
distance = [..] #distance between source and target nodes
G = nx.Graph()
path, length = [], []
for a, b, c in zip(id_a, id_b, distance):
G.add_edge(a, b, weight=c)
cl is a subset of all the nodes in the graph and I want to extract the paths interconnecting all of cl together so I use all_simple_paths()
path = []
for i in range(len(cl)):
for j in range(len(cl)):
if i != j:
path.append(nx.all_simple_paths(G, source=cl[i], target=cl[j]))
I want to be able to list all the simple paths and their lengths so I try:
for i in range(len(path)):
total_length = 0
for j in range(len(path[i])-1):
source, target = path[i][j], path[i][j+1]
edge = G[source][target]
length = edge['weight']
total_length += length
length.append(total_length)
But I keep getting the error
object of type 'generator' has no len()
And I can't figure out how to convert the generator of all_simple_paths() to lists that I can iterate over and extract the full lengths of all the paths.
Any help is appreciated!
If you read the documentation of all_simple_paths, you will see that it returns a generator. So, just use extend instead of append method like this
path = []
for i in range(len(cl)):
for j in range(len(cl)):
if i != j:
path.extend(nx.all_simple_paths(G, source=cl[i], target=cl[j]))
For more info on why extend works in this case, see this answer.
Also I see in the last part of your code, you are setting length as length = edge['weight'], then appending using length.append(total_length). This will return as error, since the edge weight will be an int. Use different variable names something like this
path_weight = [] #<----- List to store all path's weights
for i in range(len(path)):
total_length = 0
for j in range(len(path[i])-1):
source, target = path[i][j], path[i][j+1]
edge = G[source][target]
length = edge['weight'] #<--- Get the weight
total_length += length
path_weight.append(total_length) #Append to the list

Euler 4, Modulo issue

Newbie programmer fresh off of code academy. I wanted to keep going so I started the Euler examples. I've got to no.4, https://projecteuler.net/problem=4:
My program is getting to the number 980089 happily enough but decides that this number is divisible by 994. But the other value is actually 986.0050302. That isn't the answer that I'm looking for. So modulo isn't doing its job because there is a remainder of 0.0050302. Why is this happening?
Full code:
x = 999998
g = 2
while g < 99:
e = str(x)
if e[::-1] == str(x):
print(e)
for f in reversed(range(100, 1000)):
f = float(f)
h = x/f
if int(x) % f == 0.000000 and h < 1000:
print("%s and %s" % (f, h))
break
else:
x = x - 1
else:
x = x - 1
Tips on how I could improve my code would be great too, I don't think my while command was used how I originally imagined.
It looks like the general idea of what you're trying to do is to start at a number larger than anything two 3-digit numbers could multiply to, and then just start going down by one seeing if there are any possible 3-digit numbers that will multiply to your current number.
First thing I notice is that your while loop uses g, but you never modify it inside your loop, so it's rather useless. I also notice you're casting x to an int using int(x) at one point, which is not needed because x will always already be an int.
I'm going to try and rewrite your code to do the right thing - let me know if you have any questions about it!
x = 999998
found_an_answer = False
# We'll certainly find an answer before we get here
while x > 10000:
# get the string version of the number
x_string = str(x)
# See if its the same as its reverse
if x_string == x_string[::-1]:
# Print out the palindrome we're currently looking at
print ("Looking for 3-digit factors of " + x_string)
# Let's try all the factors from 999 to 100
for f in reversed(range(100, 1000)):
# First, check if f is a factor of x by checking if the
# remainder is 0 when we divide x by f.
# Then, check if the other factor, x/f, is less than 1000
# to make sure it is three digits
if x%f == 0 and x/f < 1000:
# If we made it here, we found the number!!
print("Found the number!")
print("Number: {}".format(x))
print("Factors: {}, {}".format(f, x/f))
# We set this to be true because using a "break"
# statement will only break out of the inner most
# loop (the one where we're modifying f
found_an_answer = True
break
# Now that we left the inner loop, we can check the
# found_an_answer variable to see if we should
# break out of the outer loop to.
if found_an_answer:
break
# Guess we didn't find an answer yet. LEt's look at the next
# smallest number.
x = x-1
One more little thing - instead of having using a while loop and manually decreasing x inside it, you could just do a for loop counting down, by changing the loop to be
for x in range(999998, 10000, -1):
Then you don't need the x=999998 line or the x = x-1 line.

Resources