I have started to implement backwards Dijkstra's algorithm in python:
def backwardsDijkstra(g: DoubleDictGraph, s, t):
q = PriorityQueue()
dist = {}
next = {}
q.add(t, 0)
dist[t] = 0
found = False
while not q.isEmpty() and not found:
x = q.pop()
for y in g.parseNin(x):
if y not in dist.keys() or dist[x] + g.Cost(x, y) < dist[y]:
dist[y] = dist[x] + g.Cost(x, y)
q.add(y, dist[y])
next[y] = x
if x == t:
found = True
return dist[s], next
And I can't figure out why it stops at the second iteration for the next graph for example:
5 7
0 1 5
0 2 20
1 2 10
1 3 30
2 3 5
2 4 20
3 4 10
(number of vertices, number of edges, (start,end,cost)
The bug in you code is at this line:
if x == t:
found = True
Since you are starting from t (target), you should be looking for s (source). Currently you are breaking out of the loop for the first candidate (which is t).
Related
Got task to find indexes of value and double that value in input list.
In input first line we get list range, second - list of values, third - value to find.
The output is 2 numbers - indexes of equal or higher value and double the value. If there is none, return -1
Example input:
6
1 2 4 4 6 8
3
Example output:
3 5
What i got so far is standart binary search func, but i dont get how to make it search not only for exact number but nearest higher.
def binarySearch(arr, x, left, right):
if right <= left:
return -1
mid = (left + right) // 2
if arr[mid] >= x:
return mid
elif x < arr[mid]:
return binarySearch(arr, x, left, mid)
else:
return binarySearch(arr, x, mid + 1, right)
def main():
n = int(input())
k = input().split()
q = []
for i in k:
q.append(int(i))
s = int(input())
res1 = binarySearch(q, s, q[0], (n-1))
res2 = binarySearch(q, (s*2), q[0], (n-1))
print(res1, res2)
if __name__ == "__main__":
main()
The input is:
6
1 2 4 4 6 8
3
And output:
3 4
Here's a modified binary search which will return the base zero index of a value if found or the index of the next highest value in the list.
def bsearch(lst, x):
L = 0
R = len(lst) - 1
while L <= R:
m = (L + R) // 2
if (v := lst[m]) == x:
return m
if v < x:
L = m + 1
else:
R = m - 1
return L if L < len(lst) else -1
data = list(map(int, '1 2 4 4 6 8'.split()))
for x in range(10):
print(x, bsearch(data, x))
Output:
0 0
1 0
2 1
3 2
4 2
5 4
6 4
7 5
8 5
9 -1
This is my Dijkstra's implementation. It's passing all cases in the pytest input.n.txt files but when I submit to the grading software (that doesn't provide the test or any output) I get an invalid result.
Here's my solution (passes all provided test cases, but not hidden ones).
# Uses python3
import queue
import sys
from math import inf
def dijkstra(adj, cost, s, t):
seen = set([s])
dist = [inf] * len(adj)
dist[s] = 0
prev = [None] * len(adj)
prev[s] = s
q = queue.Queue()
q.put(s)
while not q.empty():
n = q.get()
# print(n)
edges = []
for i, adjacent in enumerate(adj[n]):
edges.append([adjacent, cost[n][i]])
for i, edge in enumerate(edges):
d = dist[n] + edge[1]
if d < dist[edge[0]]:
dist[edge[0]] = d
edge[1] = d
prev[edge[0]] = n
edges = sorted(edges, key=lambda x: x[1])
for (e, w) in edges:
if not e in seen:
seen.add(e)
q.put(e)
# print(dist)
# print(prev)
return dist[t] if dist[t] is not inf else -1
def parse(input):
data = list(map(int, input.split()))
n, m = data[0:2]
data = data[2:]
edges = list(zip(zip(data[0 : (3 * m) : 3], data[1 : (3 * m) : 3]), data[2 : (3 * m) : 3]))
data = data[3 * m :]
adj = [[] for _ in range(n)]
cost = [[] for _ in range(n)]
for ((a, b), w) in edges:
adj[a - 1].append(b - 1)
cost[a - 1].append(w)
s, t = data[0] - 1, data[1] - 1
return dijkstra(adj, cost, s, t)
if __name__ == "__main__":
input = sys.stdin.read()
print(parse(input))
def test_parse():
assert 3 == parse(open("input.txt").read())
assert 6 == parse(open("input.1.txt").read())
assert -1 == parse(open("input.2.txt").read())
assert 3 == parse(open("input.3.txt").read())
assert 0 == parse(open("input.4.txt").read())
assert 0 == parse(open("input.5.txt").read())
The format of the input is as follows...
number_of_vertices number_of_edges
from to weight
from to weight
start end
input.txt
4 4
1 2 1
4 1 2
2 3 2
1 3 5
1 3
input.1.txt
5 9
1 2 4
1 3 2
2 3 2
3 2 1
2 4 2
3 5 4
5 4 1
2 5 3
3 4 4
1 5
input.2.txt
3 3
1 2 7
1 3 5
2 3 2
3 2
input.3.txt
5 5
1 2 1
1 3 2
2 3 1
2 4 6
3 4 1
1 4
input.4.txt
5 6
1 2 1
1 3 2
2 3 1
2 4 6
3 4 1
1 1 2
1 1
input.5.txt
4 4
1 2 1
2 3 1
3 4 1
4 1 1
1 1
My program passes ALL of these. And I've tried messing around with all the edge cases I can think of testing but still it fails with a "Wrong answer" error in the testing software.
One of the comments of the thread of somebody who DID solve it:
Wow! I really struggled to put this one together, not because I didn't
understand the Dijkstra algorithm but because of the difficulty in
adjusting the priority of an item already added to a Python
PriorityQueue class (whose use was implied by importing queue in the
start code) or by keeping track of its position in the priority queue,
which made translating the algorithm, as presented in the lectures,
verbatim difficult.
In case it is helpful to others, the way I got around this was to move
from thinking in terms of inserting vertices to the priority queue to
inserting references to the vertices, with most updated distance at
the time of insertion as the priority, instead. That way we don't need
to adjust the priority of an item already added to the queue at a
later time.
We may end up inserting several references to the same vertex to the
queue, but we will, of course, encounter the reference with the least
distance first, and we can ignore any future references to the same
vertex that we might encounter afterwards. Further, we can abort the
algorithm as soon as we've popped a reference to the destination
vertex.
This still runs pretty efficiently (for me, a maximum time of about a
twentieth of that allowed), and is, in retrospect, a small adjustment
in viewing the problem.
Your algorithm uses a queue; Dijkstra's algorithm does not use a queue.
At each iteration you must select the unconfirmed vertex with the shortest path distance. This can be done using a min-priority queue, where the path distance is the priority, but note also that each vertex may have to be added to the priority queue more than once if it is discovered via different paths of different distances. (Your classmate initially tried to do this the hard way - by updating the priority of a vertex already in the priority queue, instead of just allowing each vertex to be present in the priority queue multiple times.)
So your algorithm is not a proper implementation of Dijkstra's algorithm, because it confirms the vertices in the order they are discovered, rather than in order of path distance from the source vertex.
I was going through this problem on SPOJ.
It is a problem about binary search.
I tried to implement this in python:
x,yu= input().split()
bu=int(yu)
y=int(yu)
array=input().split()
while y>0:
qquery=input()
y=y-1
query=int(qquery)
b= int(x)
left=1
right= b
while left <= right and bu>0:
pmid=((right+left)/2-1)
mid=int(pmid)
fir=array[mid]
fire=int(fir)
if fire== query:
bu=bu-1
if query < fire:
left=mid+1
else :
right=mid-1
this is the input:
5 4
2 4 7 7 9
7
10
4
2
I am getting an infinite loop with 3.
I have been stuck on this problem for a long time. I would really like someone to point out my mistake, the solution and the explanation.
Thank you!!
Try this code if you're looking for the binary search algorithm.
def binary_search(seq, t):
min = 0
max = len(seq) - 1
while True:
if max < min:
return -1
m = (min + max) // 2
if seq[m] < t:
min = m + 1
elif seq[m] > t:
max = m - 1
else:
return m
seq = [1, 2, 3, 4]
t = 2
binary_search(seq, t)
I'm trying to write an algorithm that will find the path in n*n matrix with minimum cost (every coordinate has a pre-defined cost). Cost of path is defined as the sum of all coordinate costs. The first line of input contains the size of a matrix and the following n lines are table rows. Last two lines of code are 1. begin coordinates 2. end coordinates. Output is the minimum path cost.
Example input :
5
0 1 2 1 1
0 0 1 5 1
1 0 0 1 1
1 1 0 7 0
1 8 0 0 0
0 0
4 4
Output should be 0
This is code with memoization (it works without memoization but it's slow)
import copy
import sys
sys.setrecursionlimit(9000)
INF = 100000
n = int(input())
memo = {}
def input_matrix(n) :
p = []
for i in range(n) :
p.append(list(map(int, input().split())))
return p
def min_cost(matrix, x, y, end_x, end_y) :
if x == end_x and y == end_y :
return 0
if (x, y) in memo :
return memo[(x, y)]
if x == len(matrix) or y == len(matrix) or x == -1 or y == -1 or matrix[y][x] == -1:
return INF
z = copy.deepcopy(matrix)
z[y][x] = -1
memo[(x, y)] = min(
min_cost(z, x+1, y, end_x, end_y)+matrix[y][x],
min_cost(z, x-1, y, end_x, end_y)+matrix[y][x],
min_cost(z, x, y+1, end_x, end_y)+matrix[y][x],
min_cost(z, x, y-1, end_x, end_y)+matrix[y][x]
)
return memo[(x, y)]
matrix = input_matrix(n)
begin_coords = list(map(int, input().split()))
end_coords = list(map(int, input().split()))
print(min_cost(matrix, begin_coords[0], begin_coords[1], end_coords[0], end_coords[1]))
The problem is that your use of the cache is not correct. Consider the following example, in which your code returns 1 instead of 0:
3
0 0 1
1 0 0
1 1 0
0 0
2 2
If you try to follow the code flow you'll see that your algorithms searches the matrix in the following way:
0 -> 0 -> 1 -> x
|
1 <- 0 <- 0 -> x
|
1 -> 1 -> 0
Moreover you are setting the value in the matrix at -1 when you perform the recursive call, so when you finally reach the goal the matrix is:
-1 -1 -1
-1 -1 -1
-1 -1 0
Sure, you are copying the matrices, but during a recursive call the whole path followed to reach that point will still be -1.
I.e. when your code finds 2, 2 it returns 0. The call on 1, 2 tries to compute the value for 0, 2 but returns inf because the bottom-left corner is -1, the call on 1, 3 and 1, 1 return +inf too. So for x=1, y=2 we get the correct value 1. The code backtracks, obtaining the matrix:
-1 -1 -1
-1 -1 -1
-1 1 0
And we have 1,2 -> 1 in our memo. We have to finish the call for 0, 2, which again tries -1, 2, 0, 3 and 0, 1 all of these return +inf and hence we compute 0 2 -> 2 which is correct.
Now however things start to go wrong. The call at 0, 1 has already tried to go 1, 1 but that returns +inf since the value is set to -1, the same holds for all other recursive calls. Hence we set 0, 1 -> 3 which is wrong.
Basically by setting the value in the matrix to -1 during recursive calls you have prevent the recursive call for 0, 1 to go right and get the correct value of 1.
The issue appears in the cached version because now *every time we return to 0 1 we get the wrong value. Without cache the code is able to reach 0 1 by a path not coming from 1 1 and hence discover that 0 1 -> 1.
Instead of cachine I would use a dynamic programming approach. Fill the matrix with +inf values. Start at the goal position and put a 0 there, then compute the neighbouring values by row/column:
def min_cost(matrix, x, y, end_x, end_y):
n = len(matrix)
memo = [[float('+inf') for _ in range(n)] for _ in range(n)]
memo[end_y, end_x] = 0
changed = True
while changed:
changed = False
for x in range(n):
for y in range(n):
m = matrix[y][x]
old_v = memo[y][x]
memo[y][x] = min(
memo[y][x],
m + min(memo[h][k] for h in (y-1, y+1) if 0 <= h < n for k in (x-1, x+1) if 0 <= k < n)
)
if memo[y][x] != old_v:
changed = True
return memo[y, x]
However this is still not as efficient as it could be. If you apply dynamic programming correctly you will end up with the Bellman-Ford Algorithm. Your grid is just a graph where each vertex x, y has four outgoing edges (except those on the border).
Working on a project for CS1 that prints out a grid made of 0s and adds shapes of certain numbered sizes to it. Before it adds a shape it needs to check if A) it will fit on the grid and B) if something else is already there. The issue I am having is that when run, the function that checks to make sure placement for the shapes is valid will always do the first and second shapes correctly, but any shape added after that will only "see" the first shape added when looking for a collision. I checked to see if it wasnt taking in the right list after the first time but that doesnt seem to be it. Example of the issue....
Shape Sizes = 4, 3, 2, 1
Python Outputs:
4 4 4 4 1 2 3 0
4 4 4 4 2 2 3 0
4 4 4 4 3 3 3 0
4 4 4 4 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
It Should Output:
4 4 4 4 3 3 3 1
4 4 4 4 3 3 3 0
4 4 4 4 3 3 3 0
4 4 4 4 2 2 0 0
0 0 0 0 2 2 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
What's going on here? Full Code is below...
def binCreate(size):
binlist = [[0 for col in range(size)] for row in range(size)]
return binlist
def binPrint(lst):
for row in range(len(lst)):
for col in range(len(lst[row])):
print(lst[row][col], end = " ")
print()
def itemCreate(fileName):
lst = []
for i in open(fileName):
i = i.split()
lst = i
lst = [int(i) for i in lst]
return lst
def main():
size = int(input("Bin Size: "))
fileName = str(input("Item Size File: "))
binList = binCreate(size)
blockList = itemCreate(fileName)
blockList.sort(reverse = True)
binList = checker(binList, len(binList), blockList)
binPrint(binList)
def isSpaceFree(binList, r, c, size):
if r + size > len(binList[0]):
return False
elif c + size > len(binList[0]):
return False
for row in range(r, r + size):
for col in range(c, c + size):
if binList[r][c] != 0:
return False
elif binList[r][c] == size:
return False
return True
def checker(binList, gSize, blockList):
for i in blockList:
r = 0
c = 0
comp = False
while comp != True:
check = isSpaceFree(binList, r, c, i)
if check == True:
for x in range(c, c+ i):
for y in range(r, r+ i):
binList[x][y] = i
comp = True
else:
print(c)
print(r)
r += 1
if r > gSize:
r = 0
c += 1
if c > gSize:
print("Imcompadible")
comp = True
print(i)
binPrint(binList)
input()
return binList
Your code to test for open spaces looks in binList[r][c] (where r is a row value and c is a column value). However, the code that sets the values once an open space has been found sets binList[x][y] (where x is a column value and y is a row value).
The latter is wrong. You want to set binList[y][x] instead (indexing by row, then column).
That will get you a working solution, but it will still not be exactly what you say you expect (you'll get a reflection across the diagonal). This is because your code updates r first, then c only when r has exceeded the bin size. If you want to place items to the right first, then below, you need to swap them.
I'd suggest using two for loops for r and c, rather than a while too, but to make it work in an elegant way you'd probably need to factor out the "find one item's place" code so you could return from the inner loop (rather than needing some complicated code to let you break out of both of the nested loops).