Breadth first search: shortest reach hackerrank - python

Given an undirected graph consisting of N nodes (labelled 1 to N) where a node S represents the start position and an edge between any two nodes is of length 6 units in the graph. Problem here.
It is required to calculate the shortest distance from start position (Node S) to all of the other nodes in the graph.
Solution: This clearly is an application of floyd algorithm for minimum distances.
What I've tried: I have tried below code and it is passing 2 testcases but failing in all other test cases. I am at my wits end as to the sneaky bug. I just want hint towards the solution. It would be nice to provide hints to other ways to solve this with respect to complexity but I am looking for a sneaky bug with the current code.
def short_paths(cost, nodes):
for i in range(1, nodes):
for j in range(1, nodes):
for k in range(1, nodes):
if cost[i][j] > cost[i][k]+cost[k][j]:
cost[i][j] = cost[i][k]+cost[k][j]
return cost
tests = int(input())
while tests:
x = input().split(" ")
nodes, edges = int(x[0]), int(x[1])
#initialize everything with infinity
dp = [[1<<31 for i in range(nodes+1)] for i in range(nodes+1)]
#distance between self is 0
for i in range(nodes+1):
dp[i][i] = 0
while edges:
p = input().split(" ")
x, y = int(p[0]), int(p[1])
#undirected graph
dp[x][y] = 6
dp[y][x] = 6
edges -= 1
src = int(input())
dp = short_paths(dp, nodes+1)
result = []
for i in range(1, nodes+1):
if src != i:
if dp[src][i] == 1<<31:
result.append("-1")
else:
result.append(dp[src][i])
print(" ".join(str(e) for e in result))
tests -= 1

I think there is a problem in these lines:
for i in range(1, nodes):
for j in range(1, nodes):
for k in range(1, nodes):
You should iterate over k first in order for the result to be correct:
Try:
for k in range(1, nodes):
for i in range(1, nodes):
for j in range(1, nodes):
As the DP uses previous results it turns out that the order of the iteration is crucial to get the correct results.
The way I remember the order is to think that the k^th iteration of the algorithm computes the shortest path from i to j using just intermediate nodes just from positions 1 to k.
However, for this problem this O(N^3) approach will timeout. A better approach is to perform a breadth first search from the starting location which will have complexity of N+M instead.

import queue
def BFS(s):
q = queue.Queue()
q.put(s)
visited[s] = True
dist[s] = 0
while not q.empty():
u = q.get()
for v in graph[u]:
if not visited[v]:
visited[v] = True
q.put(v)
dist[v] = dist[u] + 1
Q = int(input())
for _ in range(Q):
n, m = map(int, input().split())
graph = [[] for i in range(n)]
visited = [False for i in range(n)]
dist = [-1 for i in range(n)]
for i in range(m):
u, v = map(lambda x: int(x) - 1, input().split())
graph[u].append(v)
graph[v].append(u)
s = int(input()) - 1
BFS(s)
for i in range(n):
if i == s:
continue
print(dist[i]*6 if dist[i] != -1 else '-1', end = ' ')
print()
Just use normal BFS

Related

Absolute value of a difference in gurobi with abs_() not working

I've got a problem with a gurobi program which is supposed to find a certain number of distinct shortest paths in a graph with a length not exceeding maxLength by using an LP. For making sure that the different paths are distinct I tried to sum up the number of arcs where one path is different from another. y[a,i,j] should be one if paths i and j are different in arc a and zero otherwise.
I tried to achieve that by taking the difference between x[a,i] and x[a,j] at every arc and then expect the sum over all arcs for every combination of i and j to be greater one. Everything above that are just constraints for a regular min cost flow. Somehow my problem is infeasible for any of the test instances if I want more than 1 path. Any ideas? Thanks in advance.
def findXShortestPaths(V, A, pred, succ, start, end, cost, amount, maxLength, origin, destination):
model = Model("Shortest Path")
I = range(amount)
x = model.addVars(A, I, vtype = GRB.BINARY, name = "x")
y = model.addVars(A, I, I, vtype = GRB.INTEGER, name = "y")
z = model.addVars(A,I,I,vtype=GRB.BINARY,name="z")
model.setObjective(quicksum(cost[a] * x[a, i] for a in A for i in I), GRB.MINIMIZE)
model.addConstrs(quicksum(x[a,i] for a in pred[v]) - quicksum(x[a,i] for a in succ[v]) == 0 for i in I for v in V if v != origin and v != destination)
model.addConstrs(quicksum(x[a,i] for a in succ[origin]) == 1 for i in I)
model.addConstrs(quicksum(x[a,i] for a in pred[destination]) == 1 for i in I)
model.addConstrs(x[a,i] + x[b,i] <= 1 for i in I for a in A for b in A if end[a] == start[b] and end[b] == start[a])
model.addConstrs(y[a,i,j]==x[a,i]-x[a,j] for a in A for i in I for j in I)
model.addConstrs(z[a,i,j]== abs_(y[a,i,j]) for a in A for i in I for j in I)
model.addConstrs(quicksum(z[a,i,j] for a in A) >= 1 for i in I for j in I if i != j)
model.addConstrs(quicksum(x[a,i]*cost[a] for a in A) <= maxLength for i in I)
model.optimize()

Exact cover problem given the cost of the groups and the cost of the elements

How to solve set cover if each group and each element has its own cost.
I came up with a greedy algorithm for this, but it does not work in all cases. Need an accurate algorithm.
That's all I could find on this topic:
this and this
But there the algorithm does not work considering the cost of the groups, and the cost of each element separately.
Please tell me what I can use to solve this problem.
from queue import PriorityQueue
N = int(input())
dct = {}
groups = PriorityQueue()
for i in range(N):
a,c = [int(j) for j in input().split()]
dct[a] = c
M = int(input())
for i in range(M):
k,c = [int(j) for j in input().split()]
s = 0
tmp = []
for j in input().split():
j_=int(j)
if j_ in dct:
s+=dct[j_]
tmp.append(j_)
d = c-s
if d<0:
groups.put([d, c, tmp])
s = 0
while not groups.empty():
#print(dct)
#for i in groups.queue:
# print(i)
g = groups.get()
if g[0]>0:
break
#print('G',g)
#print('-------')
for i in g[2]:
if i in dct:
del(dct[i])
s += g[1]
groups_ = PriorityQueue()
for i in range(len(groups.queue)):
g_ = groups.get()
s_ = 0
tmp_ = []
for i in g_[2]:
if i in dct:
s_+=dct[i]
tmp_.append(i)
d = g_[1]-s_
groups_.put([d, g_[1], tmp_])
groups = groups_
for i in dct:
s+=dct[i]
print(s)

Converting BFS to Djikstra to find the shortest path

How can I convert the following BFS algorithm to find the shortest path using Djikstra? I know that I need to update distances of neighbors, but I am confused on how exactly to extend the following BFS with it. The constraint is we can move only along L shaped paths between two nodes.
from collections import deque
N = 8
board_p = [[(-1,-1) for f in range(0,N)] for i in range(0,N)]
def Adjacents(u):
adj = []
for e in [(-2,-1),(-2,1),(2,1),(2,-1),(-1,-2),(1,-2),(-1,2),(1,2)]:
v = (u[0] + e[0], u[1] + e[1])
if v[0] >= 0 and v[0] < N and v[1] >= 0 and v[1] < N: adj.append(v)
return adj;
def Moves(s,t):
q = deque()
q.append(s)
board_p[s[0]][s[1]] = s # "root" of BFS-traversal points to it self (avoid loop over "back-edge" to s)
while q:
u = q.popleft()
if u == t: break
for v in Adjacents(u):
if board_p[v[0]][v[1]] == (-1,-1):
board_p[v[0]][v[1]] = u
q.append(v)
# walk the path back (using parent "pointers")
path = [(t)]
while t != s:
t = board_p[t[0]][t[1]]
path.append(t)
path.reverse()
return path
print(Moves((1,1),(5,5)))

Faster algorithm for finding number of paths between two nodes

I am trying to answer a question on an online judge in Python, but I am exceeding both the time limit and memory limit. The question is pretty much asking for the number of all paths from a start node to an end node. Full question specifications can be seen here.
This is my code:
import sys
lines = sys.stdin.read().strip().split('\n')
n = int(lines[0])
dict1 = {}
for i in xrange(1, n+1):
dict1[i] = []
for i in xrange(1, len(lines) - 1):
numbers = map(int, lines[i].split())
num1 = numbers[0]
num2 = numbers[1]
dict1[num2].append(num1)
def pathfinder(start, graph, count):
new = []
if start == []:
return count
for i in start:
numList = graph[i]
for j in numList:
if j == 1:
count += 1
else:
new.append(j)
return pathfinder(new, graph, count)
print pathfinder([n], dict1, 0)
What the code does is it starts at the end node, and works its way up to the top by exploring all neighboring nodes. I made essentially a breadth first search algorithm, but its taking up too much space and time. How can I improve this code to make it more efficient? Is my approach wrong and how should I fix it?
Since the graph is acyclic there is a topological ordering which we can immediately see to be 1, 2, ..., n. So we can use dynamic programming the same way it is used to solve the longest path problem. In a list paths the element paths[i] stores how many paths would there be from 1 to i. The update would be simple - for each edge (i,j) where i is from our topological order we do paths[j] += path[i].
from collections import defaultdict
graph = defaultdict(list)
n = int(input())
while True:
tokens = input().split()
a, b = int(tokens[0]), int(tokens[1])
if a == 0:
break
graph[a].append(b)
paths = [0] * (n+1)
paths[1] = 1
for i in range(1, n+1):
for j in graph[i]:
paths[j] += paths[i]
print(paths[n])
Note that what you are implementing is not actually BFS since you don't mark which vertices you've visited making your start to grow out of proportion.
Test the graph
for i in range(1, n+1):
dict1[i] = list(range(i-1, 0, -1))
If you print the size of start you can see that the max value it gets for a given n grows exactly as binomial(n, floor(n/2)) which is ~4^n/sqrt(n). Note also that BFS is not what you want since it is not possible to count the number of paths in that way.
import sys
from collections import defaultdict
def build_matrix(filename, x):
# A[i] stores number of paths from node x to node i.
# O(n) to build parents_of_node
parents_of_node = defaultdict(list)
with open(filename) as infile:
num_nodes = int(infile.readline())
A = [0] * (num_nodes + 1) # A[0] is dummy variable. Not used.
for line in infile:
if line == "0 0":
break
u, v = map(int, line.strip().split())
parents_of_node[v].append(u)
# Initialize all direct descendants of x to 1
if u == x:
A[v] = 1
# Number of paths from x to i = sum(number of paths from x to parent of i)
for i in xrange(1, num_nodes + 1): # O(n)
A[i] += sum(A[p] for p in parents_of_node[i]) # O(max fan-in of graph), assuming O(1) for accessing dict.
# Total time complexity to build A is O(n * (max_fan-in of graph))
return A
def main():
filename = sys.argv[1]
x = 1 # Find number of paths from x
y = 4 # to y
A = build_matrix(filename, x)
print(A[y])
What you are doing is a DFS (not a BFS) in that code...
Here's a link to a good solution...
EDITED:
Use this approach instead...
http://www.geeksforgeeks.org/find-paths-given-source-destination/

Splitting math sums with python

This is a simple question that has been bothering me for a while now.
I am attempting to rewrite my code to be parallel, and in the process I need to split up a sum to be done on multiple nodes and then add those small sums together. The piece that I am working with is this:
def pia(n, i):
k = 0
lsum = 0
while k < n:
p = (n-k)
ld = (8.0*k+i)
ln = pow(16.0, p, ld)
lsum += (ln/ld)
k += 1
return lsum
where n is the limit and i is an integer. Does anyone have some hints on how to split this up and get the same result in the end?
Edit: For those asking, I'm not using pow() but a custom version to do it efficiently with floating point:
def ssp(b, n, m):
ssp = 1
while n>0:
if n % 2 == 1:
ssp = (b*ssp) % m
b = (b**2) % m
n = n // 2
return ssp
Since the only variable that's used from one pass to the next is k, and k just increments by one each time, it's easy to split the calculation.
If you also pass k into pia, then you'll have both a definable starting and ending points, and you can split this up into as many pieces as you want, and at the end, add all the results together. So something like:
# instead of pia(20000, i), use pia(n, i, k) and run
result = pia(20000, i, 10000) + pia(10000, i, 0)
Also, since n is used to both set the limits and in the calculation directly, these two uses need to be split.
from math import pow
def pia(nlimit, ncalc, i, k):
lsum = 0
while k < nlimit:
p = ncalc-k
ld = 8.0*k+i
ln = ssp(16., p, ld)
lsum += ln/ld
k += 1
return lsum
if __name__=="__main__":
i, ncalc = 5, 10
print pia(10, ncalc, i, 0)
print pia(5, ncalc, i, 0) + pia(10, ncalc, i, 5)
Looks like I found a way. What I did was in the sum I had each node calculate a portion (ex. node one calculates k=1, node 2 k=2, node 3 k=3, node 4 k=4, node 1 k=5...) and then gathered them up and added them.

Categories