1

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
Alekhya Vemavarapu
  • 1,145
  • 1
  • 10
  • 26
noman pouigt
  • 906
  • 11
  • 25
  • Why are you trying to use Floyd-Warshall? That's a solution for the *all-pairs* shortest paths problem in a weighted graph where edges can have different weights, and where edge weights can even be negative. It's complete overkill and really slow. The problem even says breadth-first search in the title; that was a clear hint to use breadth-first search. (Also, the problem in the link gives all edges weight 6, not 66.) – user2357112 Apr 29 '16 at 19:15
  • Thanks for the tip. I will use that but wondering why the existing solution fails to provide the answer. Where did you see 66? – noman pouigt Apr 29 '16 at 19:18
  • Your question says "an edge between any two nodes is of length 66 units". The link says something different. – user2357112 Apr 29 '16 at 19:20
  • @user2357112 modified. Thanks. – noman pouigt Apr 29 '16 at 19:22
  • What's up with all the occurrences of `nodes+1`? – user2357112 Apr 29 '16 at 19:23
  • @user2357112 that is because nodes are from 1 and not 0. So just making sure it runs up till nodes. – noman pouigt Apr 29 '16 at 19:24
  • Then what's up with all the *non*-occurrences of `nodes+1` in `short_paths`? – user2357112 Apr 29 '16 at 19:26
  • It is passed already as nodes +1 as a parameter – noman pouigt Apr 29 '16 at 19:31

2 Answers2

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.

Peter de Rivaz
  • 33,126
  • 4
  • 46
  • 75
  • Nope, check the value I am passing to this function – noman pouigt Apr 29 '16 at 18:57
  • You are right - I've proposed an alternative correction – Peter de Rivaz Apr 29 '16 at 18:59
  • Sorry but I am afraid, how is this different ? – noman pouigt Apr 29 '16 at 19:01
  • Yes but I am not getting timed out. Just that the answers are not matching. I will use BFS anyway but just out of curiosity what is wrong with current solution using Floyd ? – noman pouigt Apr 29 '16 at 19:20
  • I believe the only problem is the order of iteration. Have you tried it with the variables in the order I suggested? – Peter de Rivaz Apr 29 '16 at 19:25
  • sorry but that makes no sense. i, j and k is iterating from 1 to nodes in your case as well as in my case. Anyway will give it a try. – noman pouigt Apr 29 '16 at 19:26
  • wow it passed all the test cases but wondering what is the difference? I just changed the order and it worked. How? If you can put the explanation then i will mark this answer correct. – noman pouigt Apr 29 '16 at 20:39
  • Consider the shortest path between 1 and 2. Your ordering works DP[1][2] out very early on in the algorithm but only considers paths that involve one intermediate node, so it will fail if the true shortest path involves more nodes. – Peter de Rivaz Apr 29 '16 at 21:00
1
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