0

I am trying to solve the following question using BackTracking in C but I don't know how to continue from here...

The question is:

Chris is planning to travel in a country with N cities. He will get help from a matrix NxN that the cell (I,J) represents the length of the road from city I to City J. The length of the road from City A to city B is not the same when compared to the road from City B to City A. The Road From the same source city back to it (directly) is 0. Chris noticed that the shortest road From A to B isn't alway the direct one between both Cities. You will need to help Chris Finding the shortest path. Write a function that checks for the shortest map given a matrix NxN which stores the values of the roads lengths. Note: N is defined as 4.

Example:

The Shortest path from 0 to 1 is going to City 0 then 3 then 1 if given the following matrix:

0 5 2 2

1 0 1 1

1 2 0 1

1 1 2 0

Her's my code:

int ShortestPath (int SourceCity, int DestinationCity, int Distance [][N], bool Chosen[][N])
{
    int Path=0;
    if (SourceCity==DestinationCity)
    {
        Distance[SourceCity][DestinationCity]=true;
        return 0;
    }

    for (int i=0;i<N;i++)
    {
        for (int j=0;j<N;j++)
        {
            Path += Distance[i][j];
            if (!Chosen[i][j])
            {
                Chosen[i][j] = true;
                ShortestPath(i, DestinationCity, Distance, Chosen);
            }
        }
    }
    if (Path>=Distance[SourceCity][DestinationCity])
    {
        Chosen[SourceCity,DestinationCity]=false;
        return Distance[SourceCity][DestinationCity];
    }
}

Note: the matrix chosen indicated wether I chose a specific road or not (Its initial values are all false)

  • This seems to be an interesting exercise. I do not understand what the two-demnsional array `Distance[][]` is in your implementation. You assign `true` to its elements though the elements should be `int`s. – MiCo Jan 11 '20 at 00:23
  • Also the calculation of `path` seems to be wrong. You always add all elements of the matrix (which is 20 if the matrix from the example is used), but the return value of the recursively called function is discarded... – MiCo Jan 11 '20 at 00:34
  • You have to implement dijkstra's shortest path algorithm. See https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm – chmike Jan 11 '20 at 08:20

1 Answers1

1

Here is a suggested solution. It is an implementation of the Dijkstra algorithm finding the shortest path.

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stdbool.h>

// number of nodes
#define N 4
// distance matrix from i to j for d[i][j]
int d[N][N] = {
    {0, 5, 2, 2},
    {1, 0, 1, 1},
    {1, 2, 0, 1},
    {1, 1, 2, 0},
};


// shortestPath stores in path the shortest path from start node to 
// final node using the distance matrix d. It returns the number of 
// nodes in the path.
int shortestPath(int d[N][N], int start, int final, int path[N]){
   // node previous to node i
   int prev[N];

   // initialize distance from node i to start as infinite
   int dist[N];
   for (int i = 0; i < N; i++)
       dist[i] = INT_MAX;
   dist[start] = 0;

   // initialize list of nodes done
   bool done[N];
   for (int i = 0; i < N; i++)
       done[i] = false;
   int nDone = 0;

   // while we haven’t done all nodes
   while (nDone < N) {
        // find not yet done node with minimal distance to start node
        int minDist = INT_MAX;
        int n; // node with minimum distance
        for (int i = 0; i < N; i++)
            if (!done[i] && dist[i] < minDist)
                minDist = dist[n = i];
        done[n] = true;
        nDone++;
        // we can stop when final node is done
        if (n == final)
            break;

        // for every node j...
        for (int j = 0; j < N; j++) {
            // if node j is not yet done, 
            // and distance from start to j through n is smaller to known
            if (!done[j] && dist[j] > dist[n] + d[n][j]) {
                // set new shortest distance
                dist[j] = dist[n] + d[n][j];
                // set node n as previous to node j
                prev[j] = n;
            }
        }
    }

    // get path [start, ..., final]
    int j = N;
    for (int i = final; i != start; i = prev[i])
        path[--j] = i;
    path[--j] = start;
    if (j == 0)
        return N;
    int n = N-j;
    for (int i = 0; i < n; i++, j++)
        path[i] = path[j];
    return n;
}

int main() {
    int path[N];
    int n = shortestPath(d, 0, 1, path);

    printf("path: %d", path[0]);
    for (int i = 1; i < n; i++)
        printf("->%d", path[i]);
    printf("\n");
    return 0;
}

It outputs

path: 0->3->1
chmike
  • 20,922
  • 21
  • 83
  • 106
  • Hello chmike, this is a nice solution, but it did not work on my machine... Then I initialized the local variable `n` to `0` (which was coincidentally 0 on your machine) and it worked as intended: I got the same solution. – MiCo Jan 14 '20 at 22:46
  • @MiCo was it because the compiler reported an error or a warning or because you didn't get the result ? It is true that I didn't initialise n. The compiler could complain about that, but the value n is set before it is used. – chmike Jan 15 '20 at 05:43
  • There was no warning. But I wondered why I got a strange result for the shortest path. So I checked the values and found out that n was not set in the first iteration... – MiCo Jan 15 '20 at 07:15
  • In the meantime I analyzed what the problem was.`n` is not initialized in the first round because the if-statement above is not true because dist[0] – MiCo Jan 17 '20 at 23:47
  • @MiCo That is correct, but there are other nodes unless N=1. There must be at least one node i with !done [i] && dist[i] < INT_MAX. This will override the value of n. Initializing n to 0 or leaving it initialized is the same. – chmike Jan 18 '20 at 07:07
  • You can test the behavior in https://onlinegdb.com/Hydza27WI if you remove the initilization of n to 0. – MiCo Jan 20 '20 at 23:53
  • The problem is the following: For all i, the distances are initialized: `dist[i] = INT_MAX;`. But in the critical for-loop below it is checked againt dist[i] – MiCo Jan 21 '20 at 00:00
  • You are right. dist[start] is set to 0, but done[start] is set to true. In this case n is not set. But initializing n to 0 is not the correct fix to this bug. It works here because start is 0. I must still verify, but I think the right thing to do is to remove the line done[start]=true. And initialize nDone to 0. – chmike Jan 21 '20 at 05:56
  • @MiCo I corrected the code. Setting n to 0 is not a good correction. It works just because the starting node is 0. The fix is to not set done[start] to true and set nDone to 0. – chmike Jan 21 '20 at 16:02