Search code examples
javapriority-queuebreadth-first-search

Problem with Algorithm to find minimum path of a 2d array


Question:

There are 10 people at a meetup.
Each person has levels 0 - 9 (the index of the input) and knows a few other people there.
Your job is to find the cheapest way for person 0 to meet person 9. Introductions have a cost that equals the square of the difference in levels.

Goal: Level 0 person wants to meet level 9 using the fewest possible points.
Cost: square of difference of levels
The index of the array represents the level (0-9)
the value is an array with the index of the other people each person knows.
Note that relationships are one directional (e.g. 2 can introduce you to 3 but not vice versa) e.g. Min cost: 23 Min path: [0, 1, 4, 6, 9]

 people = [
   [1, 2, 3],   # person 0 knows 1, 2, 3
   [8, 6, 4],   # person 1 knows 8, 6, 4
   [7, 8, 3],   # person 2 knows 7, 8, 3
   [8, 1],      # person 3 knows 8, 1
   [6],         # person 4 knows 6
   [8, 7],      # person 5 knows 8, 7
   [9, 4],      # person 6 knows 9, 4
   [4, 6],      # person 7 knows 4, 6
   [1],         # person 8 knows 1 
   [1, 4],      # person 9 knows 1, 4
 ]

My solution:

To use a priority queue and as well as set to track the elements that have already being visited. Basically a breadth first search approach. Also i will use a map to track the levels.

My problem

I attempt to use a priority queue but not able to traverse the 2d array with the queue. I only cover level 0 and not other levels. Below is my attempted solution

class Solution {
  public static void main(String[] args) {
    int[][] arr ={{1, 2, 3},
                  {8, 6, 4},
                  {7, 8, 3},
                  {8, 1},
                  {6},
                  {8,7},
                  {9, 4},
                  {4, 6},
                  {1},
                  {1,4}};
    
    Solution sol = new Solution();
    sol.meetUp(arr);
  }
  
  List<Integer> meetUp(int[][] arr) {
   if (arr == null || arr.length == 0)  {
     return new ArrayList<>();
  }
    
  Set<Integer> visited = new HashSet<>();
  PriorityQueue<MinQueue> pq = new PriorityQueue<>();
  Map<Integer, Integer> parentMap = new HashMap<>();
    
  pq.offer(new MinQueue(0, 0, arr[0][0]));
    
  while(!pq.isEmpty()) {
   MinQueue temp = pq.poll();
   int col = temp.col + 1;
   while (col < arr[temp.row].length) {
    if(!visited.contains(arr[temp.row][col])) {
     pq.offer(new MinQueue(temp.row, col, arr[temp.row][col])); 
     col += 1;
    }
  }
     
  if(!parentMap.containsKey(temp.row)) {
        parentMap.put(temp.row, temp.data);
      } else {
          int v = parentMap.get(temp.row);
          int n = (int)Math.pow(temp.data, 2) - (int)Math.pow(temp.row, 2);
          int o = (int)Math.pow(v, 2) - (int)Math.pow(temp.row, 2);
        if(n < o) {
          parentMap.put(temp.row, temp.data);
      }
    }
    visited.add(temp.data);
  }
    return new ArrayList<>();
  }
}

class MinQueue implements Comparable<MinQueue> {
  
   int data;
   int row;
   int col;
  
   MinQueue(int row, int col, int data) {
     this.row = row;
     this.col = col;
     this.data = data;
   }
  
  public int compareTo(MinQueue other) {
    if(this.data - other.data > 0) return 1;
    else if(this.data - other.data < 0) return -1;
    else return 0;
  }
}

Solution

  • You're looking for the minimum cost path through a directed graph. As such, Dijkstra's algorithm is what you want.

    Here's a simple Java implementation, customized to your task. It returns -1 if no path exists.

    static int minCost(int[][] relations, int[] prev)
    {
        PriorityQueue<Person> q = new PriorityQueue<>();
    
        Person[] person = new Person[relations.length];
        for(int i=0; i<relations.length; i++) 
        {
            person[i] = new Person(i, i==0 ? 0 : Integer.MAX_VALUE);
        }
    
        q.offer(person[0]);     
        while(!q.isEmpty())
        {
            Person p = q.poll();
    
            if(p.level == person.length-1) 
                return p.cost;          
    
            for(int n : relations[p.level])
            {
                int d = p.cost + (n-p.level)*(n-p.level); 
                if(d < person[n].cost)
                {
                    q.offer(person[n] = new Person(n, d));
                    prev[n] = p.level;
                }
            }
        }       
        return -1;
    }
    
    static class Person implements Comparable<Person>
    {
        public int level;
        public int cost;
    
        public Person(int level, int cost)
        {
            this.level = level;
            this.cost = cost;
        }
    
        @Override
        public int compareTo(Person o)
        {
            return cost - o.cost;
        }
    }
    
    static String buildPath(int[] arr, int i, String path)
    {
        path = i + " " + path;
        if(i == 0) return path;
        else return buildPath(arr, arr[i], path);
    }
    
    public static void main(String[] args) 
    {
        int[][] arr ={{1, 2, 3},
                      {8, 6, 4},
                      {7, 8, 3},
                      {8, 1},
                      {6},
                      {8,7},
                      {9, 4},
                      {4, 6},
                      {1},
                      {1,4}};
    
        int[] prev = new int[arr.length];
        int min = minCost(arr, prev);
        if(min < 0) System.out.println("No path");    
        else System.out.println(min + " : " + buildPath(prev, arr.length-1, ""));        
    }
    

    Output:

    23 : 0 1 4 6 9