I am working on finding the shortest path in a maze and would like someone to look over my code and comment how to make it better as well as say what would be the most efficient way to get the path back.
def aStarSearch(currentNode, endNode):
openList = []
closedList = []
currentNode.set_g(0) #cost so far
currentNode.set_h(endNode.return_y(), endNode.return_x()) #estimated euclidean distance
currentNode.set_f((currentNode.get_g() + currentNode.get_h())) #total cost
openList.append(currentNode)
closedList.append(currentNode)
while openList != []:
for node in openList:
if node.get_f() <= currentNode.get_f(): #node with smaller total cost becomes current node
currentNode = node
currentNode.set_h(endNode.return_y(), endNode.return_x()) #estimated euclidean distance
currentNode.set_f((currentNode.get_g() + currentNode.get_h())) #total cost
draw_maze(endNode)
neighbours = return_Neighbours(currentNode)
for neighbour in neighbours:
neighbour.set_f(neighbour.get_g() + neighbour.get_h()) #calculate the f cost
if neighbour.get_g() <= currentNode.get_g() and neighbour in closedList: #if the neighbours cost is smaller and in closed list mean already visited,should backtrack
openList.append(neighbour)
closedList.remove(neighbour)
neighbour.set_colour((255,0,255))
elif currentNode.get_g() <= neighbour.get_g() and neighbour in openList: #it has not been already visited but seen so g is smaller
neighbour.set_g(currentNode.get_g()) #change g because g is previous cost
closedList.append(neighbour)
neighbour.set_colour((255,255,0))
elif neighbour not in openList or closedList: #not visited yet, needs to be appended, calculate h because cannot find another place to do that
openList.append(neighbour)
neighbour.set_h(endNode.return_x(), endNode.return_y())
neighbour.set_colour((0,255,255))
if currentNode.get_vector() == endNode.get_vector():
return closedList
Related
Suppose there is a population of 500 people, and each person knows
exactly 4 other people in the population. Suppose one person gets
infected with a disease, and that disease is guaranteed to infect the
other 4 people that person knows in exactly 1 day's time.
Write an algorithm to determine how many days it takes for everybody
to be infected, given an input adjacency matrix.
I can't figure out how to properly keep track of the days. I tried the following, but it just gives me a number close to the total number of nodes (it should be much lower):
import random
random.seed(20)
nodes = 500
num_connections = 4
# generate random graph
graph = []
for node_num in range(nodes):
myrow = [0 for node in range(nodes - num_connections)] + [1 for connection in range(num_connections)]
random.shuffle(myrow)
graph.append(myrow)
days = 0
visited = [0]
queue = [0]
while queue:
ss = queue.pop(0)
for neighbor, is_connected in enumerate(graph[ss]):
if is_connected == 1 and neighbor not in visited:
visited.append(neighbor)
queue.append(neighbor)
days += 1
print(days)
What am I doing wrong?
find longest shortest path from first infected person to any other person,
using the Dijkstra algorithm.
The length of this path is the number
of days.
your problem is equivalent to finding the longest shortest route in the graph. but if you want to fix your current code, I fixed it for you :)
import random
random.seed(20)
nodes = 50
num_connections = 4
# generate random graph
graph = []
for node_num in range(nodes):
myrow = [0 for node in range(nodes - num_connections)] + [1 for connection in range(num_connections)]
random.shuffle(myrow)
graph.append(myrow)
days = 0
visited = [0]
queue = [0]
while len(visited) < nodes:
patients = queue.copy()
queue.clear()
days += 1
while len(patients) > 0:
ss = patients.pop(0)
for neighbor, is_connected in enumerate(graph[ss]):
if is_connected == 1 and neighbor not in visited:
visited.append(neighbor)
queue.append(neighbor)
if len(queue) == 0:
print(f'The given directional graph is not connected, after {days} days, {len(visited)} persons has been infected')
exit()
print(days)
Tree difference (Problem Code: TREDIFF). This is a problem from Codechef's May Lunchtime (Contest is over so Practice now). My code runs fine in other IDEs but I get a TLE error when I submit. I code in Python 3. But all help is appreciated. Here's the problem:
Problem
You are given a tree with N nodes (numbered 1 through N). For each valid i, node i has a value Ai.
You should answer Q queries. In each query:
You are given two nodes a and b.
Let S denote the set of all nodes on the simple path between the nodes a and b (including these nodes).
Find the minimum value of |Ax−Ay| over all pairs x,y∈S such that x≠y.
Input
The first line of the input contains a single integer T denoting the number of test cases. The description of T test cases follows.
The first line of each test case contains two space-separated integers N and Q.
The second line contains N space-separated integers A1,A2,…,AN.
Each of the next N−1 lines contains two space-separated integers u and v denoting that nodes u and v are connected by an edge.
Each of the last Q lines contains two space-separated integers a and b describing a query.
Output
Output
For each query, print a single line containing one integer ― the answer to the query.
Does anyone have an idea on how to make it faster?
from collections import deque
INFINITY = float("inf")
Zero = 0
class Graph:
def __init__(self, datasheet):
graph_edges = datasheet
self.nodes = set()
for edge in graph_edges:
self.nodes.update([edge[0], edge[1]])
self.adjacency_list = {node: set() for node in self.nodes}
for edge in graph_edges:
self.adjacency_list[edge[0]].add((edge[1], edge[2]))
def shortest_path(self, start_node, end_node):
unvisited_nodes = self.nodes.copy()
distance_from_start = {
node: (0 if node == start_node else INFINITY) for node in self.nodes
}
previous_node = {node: None for node in self.nodes}
while unvisited_nodes:
current_node = min(
unvisited_nodes, key=lambda node: distance_from_start[node]
)
unvisited_nodes.remove(current_node)
if distance_from_start[current_node] == INFINITY:
break
for neighbor, distance in self.adjacency_list[current_node]:
new_path = distance_from_start[current_node] + distance
if new_path < distance_from_start[neighbor]:
distance_from_start[neighbor] = new_path
previous_node[neighbor] = current_node
if current_node == end_node:
break
path = deque()
current_node = end_node
while previous_node[current_node] is not None:
path.appendleft(current_node)
current_node = previous_node[current_node]
path.appendleft(start_node)
return path, distance_from_start[end_node]
T = int(input())
for k in range(T):
N, Q = map(int, input().split())
Values = list(map(int, input().split()))
nodes = []
queries = []
datasheet = []
for i in range(N - 1):
a, b = map(int, input().split())
cost = Values[b - 1] - Values[a - 1]
datasheet.append((a, b, float(cost)))
for j in range(Q):
c = list(map(int, input().split()))
start = c[0]
end = c[1]
queries.append(c)
graph = Graph(datasheet=datasheet)
returned_path, returned_distance = graph.shortest_path(start, end)
if returned_distance == INFINITY:
print(Zero)
else:
print(int(abs(returned_distance)))
Found this problem in hackerrank and have failed to pass some testcases.
One day Bob drew a tree, with n nodes and n-1 edges on a piece of paper. He soon discovered that parent of a node depends on the root of the tree. The following images shows an example of that:
Learning the fact, Bob invented an exciting new game and decided to play it with Alice. The rules of the game is described below:
Bob picks a random node to be the tree's root and keeps the identity of the chosen node a secret from Alice. Each node has an equal probability of being picked as the root.
Alice then makes a list of g guesses, where each guess is in the form u v and means Alice guesses that parent(v) = u is true. It's guaranteed that an undirected edge connecting u and v exists in the tree.
For each correct guess, Alice earns one point. Alice wins the game if she earns at least k points (i.e., at least k of her guesses were true).
Alice and Bob play q games. Given the tree, Alice's guesses, and the value of k for each game, find the probability that Alice will win the game and print it on a new line as a reduced fraction in the format p/q.
Solution:
There is a tree with some edges marked with arrows. For every vertex in a tree you have to count how many arrows point towards it.For one fixed vertex this may be done via one DFS. Every arrow that was traversed during DFS in direction opposite to its own adds 1.If you know the answer for vertex v, you can compute the answer for vertex u adjacent to v in O(1).
It's almost the same as for v, but if there are arrows u->v or v->u, their contributions are reversed.Now you can make the vertex u crawl over the whole graph by moving to adjacent vertices in the second DFS.
Problem: It is not able to pass all the test cases. I did sanity testing of the code and found no problem but I am not getting any clue why this is not working in hackerrank platform.
import sys
def gcd(a, b):
if not b:
return a
return gcd(b, a%b)
def dfs1(m, guess, root, seen):
'''keep 1 node as root and calculate how many arrows are pointing towards it'''
count = 0
for i in m[root]:
if seen[i][root] != 1 and seen[root][i] != 1:
seen[i][root] = 1
seen[root][i] = 1
count += (1 if guess[root][i] == 1 else 0) + dfs1(m, guess, i, seen)
return count
def dfs2(m, guess, root, seen, cost, k):
'''now make every node as root and calculate how many nodes
are pointed towards it; If u is the root node for which
dfs1 calculated n (number of arrows pointed towards the root)
then for v (adjacent node of u), it would be n-1 as v is the
made the parent now in this step (only if there is a guess, if
there is no guess then it would be not changed)'''
win = cost >= k
for i in m[root]:
if seen[i][root] != 1 and seen[root][i] != 1:
seen[i][root] = 1
seen[root][i] = 1
win += dfs2(m, guess, i, seen, cost - (1 if guess[root][i] == 1 else -guess[i][root]), k)
return win
q = int(raw_input().strip())
for a0 in xrange(q):
n = int(raw_input().strip())
m = {}
guess = [[0 for i in range(n+1)] for i in range(n+1)]
seen = [[0 for i in range(n+1)] for i in range(n+1)]
for a1 in xrange(n-1):
u,v = raw_input().strip().split(' ')
u,v = [int(u),int(v)]
if u not in m:
m[u] = []
m[u].append(v)
if v not in m:
m[v] = []
m[v].append(u)
g,k = raw_input().strip().split(' ')
g,k = [int(g),int(k)]
for a1 in xrange(g):
u,v = raw_input().strip().split(' ')
u,v = [int(u),int(v)]
guess[u][v] = 1
cost = dfs1(m, guess, 1, seen)
seen = [[0 for i in range(n+1)] for i in range(n+1)]
win = dfs2(m, guess, 1, seen, cost, k)
g = gcd(win, n)
print("{0}/{1}".format(win/g, n/g))
One possibility is that the code is correct but you are getting a stack overflow.
There can be 100,000 nodes and if these are all connected in a line your depth first search recursion will fail.
If this is true, then converting the DFS code from a recursive to an iterative formulation (by keeping a stack of things to try in an array) should help.
Another possibility is that there could be a guess such as 1,2 and a guess such as 2,1. In this case I am not sure that the score updating code would work:
win += dfs2(m, guess, i, seen, cost - (1 if guess[root][i] == 1 else -guess[i][root]), k)
perhaps this would work better:
win += dfs2(m, guess, i, seen, cost - guess[root][i] + guess[i][root], k)
I have a problem concerning a labyrinth pathfinder I'm making. I have got a depth first solution, but i want a breadth first solution.
This is the depth first:
def find_path(pathList):
if pathList[-1] == goal:
return pathList
for i in adjacent_passages(labyrinth, pathList[-1]):
if i not in pathList:
found_path = find_path(pathList + [i])
if found_path:
return found_path
And this is how "far" I've come on the breadth first problem:
def find_path_bf(pathL):
num = 0
for i in range(0, len(pathL)):
frontier[i] = adjacent_passages(labyrinth, pathL[i][-1])
for i in range(0, len(pathL)):
if pathL[i][-1] == goal:
return pathL[i]
for i in frontier:
if i not in pathL:
pathL[num].append(i)
num = num + 1
find_path_bf(pathL)
The labyrinth is a matrix of a labyrinth and adjacent_passages finds the adjacent squares :)
I am trying to write Dijkstra's Algorithm, however I am struggling on how to 'say' certain things in code.
To visualize, here are the columns I want represented using arrays:
max_nodes
A B C Length Predecessor Visited/Unvisited
A 0 1 2 -1 U
B 1 0 1 -1 U
C 2 1 0 -1 U
So, there will be several arrays, as seen in my code below:
def dijkstra (graph, start, end)
network[max_nodes][max_nodes]
state [max_nodes][length]
state2 [max_nodes][predecessor]
state3 [max_nodes][visited]
initialNode = 0
for nodes in graph:
D[max_nodes][length] = -1
P[max_nodes][predecessor] = ""
V[max_nodes][visited] = false
for l in graph:
length = lengthFromSource[node] + graph[node][l]
if length < lengthFromSourceNode[w]:
state[l][length] = x
state2[l][predecessor]
state3[l][visited] = true
x +=1
The part in bold is where I am stuck on - I am trying to implement this section of the algorithm:
3. For current node, consider all its unvisited neighbors and calculate their tentative distance. For example, if current node (A) has distance of 6, and an edge connecting it with another node (B) is 2, the distance to B through A will be 6+2=8. If this distance is less than the previously recorded distance, overwrite the distance
4. When we are done considering all neighbors of the current node, mark it as visited. A visited node will not be checked ever again; its distance recorded now is final and minimal
I think I am on the right track, i'm just stuck on how to say 'start at a node, get the length from source to a node, if length is smaller, overwrite previous value, then move to next node
I also used a dictionary to store the network.
Data is in the following format:
source: {destination: cost}
create a network dictionary (user provided)
net = {'0':{'1':100, '2':300},
'1':{'3':500, '4':500, '5':100},
'2':{'4':100, '5':100},
'3':{'5':20},
'4':{'5':20},
'5':{}
}
shortest path algorithm (user needs to specify start and terminal nodes)
def dijkstra(net, s, t):
# sanity check
if s == t:
return "The start and terminal nodes are the same. Minimum distance is 0."
if s not in net: # python2: if net.has_key(s)==False:
return "There is no start node called " + str(s) + "."
if t not in net: # python2: if net.has_key(t)==False:
return "There is no terminal node called " + str(t) + "."
# create a labels dictionary
labels={}
# record whether a label was updated
order={}
# populate an initial labels dictionary
for i in net.keys():
if i == s: labels[i] = 0 # shortest distance form s to s is 0
else: labels[i] = float("inf") # initial labels are infinity
from copy import copy
drop1 = copy(labels) # used for looping
## begin algorithm
while len(drop1) > 0:
# find the key with the lowest label
minNode = min(drop1, key = drop1.get) #minNode is the node with the smallest label
# update labels for nodes that are connected to minNode
for i in net[minNode]:
if labels[i] > (labels[minNode] + net[minNode][i]):
labels[i] = labels[minNode] + net[minNode][i]
drop1[i] = labels[minNode] + net[minNode][i]
order[i] = minNode
del drop1[minNode] # once a node has been visited, it's excluded from drop1
## end algorithm
# print shortest path
temp = copy(t)
rpath = []
path = []
while 1:
rpath.append(temp)
if temp in order: temp = order[temp] #if order.has_key(temp): temp = order[temp]
else: return "There is no path from " + str(s) + " to " + str(t) + "."
if temp == s:
rpath.append(temp)
break
for j in range(len(rpath)-1,-1,-1):
path.append(rpath[j])
return "The shortest path from " + s + " to " + t + " is " + str(path) + ". Minimum distance is " + str(labels[t]) + "."
# Given a large random network find the shortest path from '0' to '5'
print dijkstra(net, s='0', t='5')
First, I assume this is a homework problem, as the best suggest is to not bother writing it yourself, but to find an existing implementation on the web. Here's one that looks pretty good, for example.
Assuming you do need to reinvent the wheel, the code referenced there uses dictionaries to store the node data. So you feed it something like:
{
's': {'u' : 10, 'x' : 5},
'u': {'v' : 1, 'x' : 2},
'v': {'y' : 4},
'x': {'u' : 3, 'v' : 9, 'y' : 2},
'y': {'s' : 7, 'v' : 6}
}
This seems a more intuitive way of presenting your graph information. Visited nodes and distances can be kept in dictionaries as well.