Minimum cost to reach from the top-left to the bottom-right corner of a matrix

Given an N * M matrix mat[][] consisting of lower case characters, the task is to find the minimum cost to reach from the cell mat[0][0] to the cell mat[N-1][M-1]. If you are at a cell mat[i][j], you can jump to the cells mat[i+1][j], mat[i][j+1], mat[i-1][j], mat[i][j-1] (without going out of bounds) with a cost of 1. Additionally, you can jump to any cell mat[m][n] such that mat[n][m] = mat[i][j] with a cost of 0.

Examples:

Input: mat[][] = {“abc”, “efg”, “hij”}
Output: 4
One of the shortest path will be:
{0, 0} -> {0, 1} -> {0, 2} -> {1, 2} -> {2, 2}
All the edges have a weight of 1, thus the answer is 4.

Input: mat[][] = {“abc”, “efg”, “hbj”}
Output: 2
{0, 0} -> {0, 1} -> {2, 1} -> {2, 2}
1 + 0 + 1 = 2

Naive approach: One approach for solving this problem will be 0-1 BFS. Visualise the setup as a graph with N * M nodes. All the nodes will be connected to adjacent nodes with an edge of weight 1 and the nodes with the same characters with an edge with weight 0. Now, BFS can be used to find the shortest path from the cell mat[0][0] to the cell mat[N-1][M-1]. The time complexity of this will be O((N * M)2) because the number of edges will be of the order O((N * M)2).



Efficient approach: For each character X, find all the characters it is adjacent to. Now, create a graph with a number of nodes as the number of distinct characters in the string each representing a character.
Each node X will have an edge of weight 1 with all the nodes representing the characters adjacent to the character X in the real graph. Then a BFS can be run from the node representing mat[0][0] to the node representing mat[N-1][M-1] in this new graph. The time complexity of this approach will be O(N * M) for pre-processing the graph and the time complexity for running the BFS can be considered constant.

Below is the implementation of the above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
  
const int MAX = 26;
  
// Function to return
// the value (x - 97)
int f(int x)
{
    return x - 'a';
}
  
// Function to return the minimum cost
int findMinCost(vector<string> arr)
{
    int n = arr.size();
    int m = arr[0].size();
  
    // Graph
    vector<vector<int> > gr(MAX);
  
    // Adjacency matrix
    bool edge[MAX][MAX];
  
    // Initialising the adjacency matrix
    for (int k = 0; k < MAX; k++)
        for (int l = 0; l < MAX; l++)
            edge[k][l] = 0;
  
    // Creating the adjacency matrix
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++) {
            if (i + 1 < n and !edge[f(arr[i][j])][f(arr[i + 1][j])]) {
                gr[f(arr[i][j])].push_back(f(arr[i + 1][j]));
                edge[f(arr[i][j])][f(arr[i + 1][j])] = 1;
            }
            if (j - 1 >= 0 and !edge[f(arr[i][j])][f(arr[i][j - 1])]) {
                gr[f(arr[i][j])].push_back(f(arr[i][j - 1]));
                edge[f(arr[i][j])][f(arr[i][j - 1])] = 1;
            }
            if (j + 1 < m and !edge[f(arr[i][j])][f(arr[i][j + 1])]) {
                gr[f(arr[i][j])].push_back(f(arr[i][j + 1]));
                edge[f(arr[i][j])][f(arr[i][j + 1])] = 1;
            }
            if (i - 1 >= 0 and !edge[f(arr[i][j])][f(arr[i - 1][j])]) {
                gr[f(arr[i][j])].push_back(f(arr[i - 1][j]));
                edge[f(arr[i][j])][f(arr[i - 1][j])] = 1;
            }
        }
  
    // Queue to perform BFS
    queue<int> q;
    q.push(arr[0][0] - 'a');
  
    // Visited array
    bool v[MAX] = { 0 };
  
    // To store the depth of BFS
    int d = 0;
  
    // BFS
    while (q.size()) {
  
        // Number of elements in
        // the current level
        int cnt = q.size();
  
        // Inner loop
        while (cnt--) {
  
            // Current element
            int curr = q.front();
  
            // Popping queue
            q.pop();
  
            // If the current node has
            // already been visited
            if (v[curr])
                continue;
            v[curr] = 1;
  
            // Checking if the current
            // node is the required node
            if (curr == arr[n - 1][m - 1] - 'a')
                return d;
  
            // Iterating through the current node
            for (auto it : gr[curr])
                q.push(it);
        }
  
        // Updating the depth
        d++;
    }
  
    return -1;
}
  
// Driver code
int main()
{
    vector<string> arr = { "abc",
                           "def",
                           "gbi" };
  
    cout << findMinCost(arr);
  
    return 0;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java implementation of the approach
import java.util.*;
  
class GFG 
{
  
    static int MAX = 26;
  
    // Function to return
    // the value (x - 97)
    static int f(int x)
    {
        return x - 'a';
    }
  
    // Function to return the minimum cost
    static int findMinCost(String[] arr) 
    {
        int n = arr.length;
        int m = arr[0].length();
  
        // Graph
        Vector<Integer>[] gr = new Vector[MAX];
        for (int i = 0; i < MAX; i++)
            gr[i] = new Vector<Integer>();
  
        // Adjacency matrix
        boolean[][] edge = new boolean[MAX][MAX];
  
        // Initialising the adjacency matrix
        for (int k = 0; k < MAX; k++)
            for (int l = 0; l < MAX; l++)
                edge[k][l] = false;
  
        // Creating the adjacency matrix
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++) 
            {
                if (i + 1 < n && !edge[f(arr[i].charAt(j))][f(arr[i + 1].charAt(j))]) 
                {
                    gr[f(arr[i].charAt(j))].add(f(arr[i + 1].charAt(j)));
                    edge[f(arr[i].charAt(j))][f(arr[i + 1].charAt(j))] = true;
                }
                if (j - 1 >= 0 && !edge[f(arr[i].charAt(j))][f(arr[i].charAt(j - 1))])
                {
                    gr[f(arr[i].charAt(j))].add(f(arr[i].charAt(j - 1)));
                    edge[f(arr[i].charAt(j))][f(arr[i].charAt(j - 1))] = true;
                }
                if (j + 1 < m && !edge[f(arr[i].charAt(j))][f(arr[i].charAt(j + 1))]) 
                {
                    gr[f(arr[i].charAt(j))].add(f(arr[i].charAt(j + 1)));
                    edge[f(arr[i].charAt(j))][f(arr[i].charAt(j + 1))] = true;
                }
                if (i - 1 >= 0 && !edge[f(arr[i].charAt(j))][f(arr[i - 1].charAt(j))]) 
                {
                    gr[f(arr[i].charAt(j))].add(f(arr[i - 1].charAt(j)));
                    edge[f(arr[i].charAt(j))][f(arr[i - 1].charAt(j))] = true;
                }
            }
  
        // Queue to perform BFS
        Queue<Integer> q = new LinkedList<Integer>();
        q.add(arr[0].charAt(0) - 'a');
  
        // Visited array
        boolean[] v = new boolean[MAX];
  
        // To store the depth of BFS
        int d = 0;
  
        // BFS
        while (q.size() > 0)
        {
  
            // Number of elements in
            // the current level
            int cnt = q.size();
  
            // Inner loop
            while (cnt-- > 0)
            {
  
                // Current element
                int curr = q.peek();
  
                // Popping queue
                q.remove();
  
                // If the current node has
                // already been visited
                if (v[curr])
                    continue;
                v[curr] = true;
  
                // Checking if the current
                // node is the required node
                if (curr == arr[n - 1].charAt(m - 1) - 'a')
                    return d;
  
                // Iterating through the current node
                for (Integer it : gr[curr])
                    q.add(it);
            }
  
            // Updating the depth
            d++;
        }
  
        return -1;
    }
  
    // Driver code
    public static void main(String[] args) 
    {
        String[] arr = { "abc", "def", "gbi" };
  
        System.out.print(findMinCost(arr));
  
    }
}
  
// This code is contributed by 29AjayKumar

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 implementation of the approach
MAX = 26
  
# Function to return
# the value (x - 97)
def f(x):
    return ord(x) - ord('a')
  
# Function to return the minimum cost
def findMinCost( arr):
    global MAX
    n = len(arr)
    m = len(arr[0])
  
    # Graph
    gr = []
      
    for x in range(MAX):
        gr.append([])
  
    # Adjacency matrix
    edge = []
  
    # Initialising the adjacency matrix
    for k in range(MAX):
        edge.append([])
        for l in range(MAX):
            edge[k].append(0)
  
    # Creating the adjacency matrix
    for i in range(n):
        for j in range(m): 
            if (i + 1 < n and edge[f(arr[i][j])][f(arr[i + 1][j])] == 0): 
                gr[f(arr[i][j])].append(f(arr[i + 1][j]))
                edge[f(arr[i][j])][f(arr[i + 1][j])] = 1
              
            if (j - 1 >= 0 and edge[f(arr[i][j])][f(arr[i][j - 1])] == 0): 
                gr[f(arr[i][j])].append(f(arr[i][j - 1]))
                edge[f(arr[i][j])][f(arr[i][j - 1])] = 1
              
            if (j + 1 < m and edge[f(arr[i][j])][f(arr[i][j + 1])] == 0): 
                gr[f(arr[i][j])].append(f(arr[i][j + 1]))
                edge[f(arr[i][j])][f(arr[i][j + 1])] = 1
              
            if (i - 1 >= 0 and edge[f(arr[i][j])][f(arr[i - 1][j])] == 0): 
                gr[f(arr[i][j])].append(f(arr[i - 1][j]))
                edge[f(arr[i][j])][f(arr[i - 1][j])] = 1
              
    # Queue to perform BFS
    q = []
    q.append(ord(arr[0][0]) - ord('a'))
  
    # Visited array
    v = []
    for i in range(MAX):
        v.append(0)
  
    # To store the depth of BFS
    d = 0
  
    # BFS
    while (len(q) > 0): 
  
        # Number of elements in
        # the current level
        cnt = len(q)
  
        # Inner loop
        while (cnt > 0): 
            cnt = cnt - 1
              
            # Current element
            curr = q[0]
  
            # Popping queue
            q.pop(0)
  
            # If the current node has
            # already been visited
            if (v[curr] != 0):
                continue
            v[curr] = 1
              
            # Checking if the current
            # node is the required node
            if (curr == (ord(arr[n - 1][m - 1]) - ord('a'))):
                return d
  
            # Iterating through the current node
            for it in gr[curr]:
                q.append(it)
          
        # Updating the depth
        d = d + 1
  
    return -1
  
# Driver code
arr =[ "abc","def","gbi" ]
print( findMinCost(arr))
  
# This code is contributed by Arnab Kundu

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# implementation of the approach
using System;
using System.Collections.Generic;
  
class GFG 
{
  
    static int MAX = 26;
  
    // Function to return
    // the value (x - 97)
    static int f(int x)
    {
        return x - 'a';
    }
  
    // Function to return the minimum cost
    static int findMinCost(String[] arr) 
    {
        int n = arr.Length;
        int m = arr[0].Length;
  
        // Graph
        List<int>[] gr = new List<int>[MAX];
        for (int i = 0; i < MAX; i++)
            gr[i] = new List<int>();
  
        // Adjacency matrix
        bool[,] edge = new bool[MAX, MAX];
  
        // Initialising the adjacency matrix
        for (int k = 0; k < MAX; k++)
            for (int l = 0; l < MAX; l++)
                edge[k,l] = false;
  
        // Creating the adjacency matrix
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++) 
            {
                if (i + 1 < n && !edge[f(arr[i][j]),f(arr[i + 1][j])]) 
                {
                    gr[f(arr[i][j])].Add(f(arr[i + 1][j]));
                    edge[f(arr[i][j]), f(arr[i + 1][j])] = true;
                }
                if (j - 1 >= 0 && !edge[f(arr[i][j]),f(arr[i][j - 1])])
                {
                    gr[f(arr[i][j])].Add(f(arr[i][j - 1]));
                    edge[f(arr[i][j]), f(arr[i][j - 1])] = true;
                }
                if (j + 1 < m && !edge[f(arr[i][j]),f(arr[i][j + 1])]) 
                {
                    gr[f(arr[i][j])].Add(f(arr[i][j + 1]));
                    edge[f(arr[i][j]), f(arr[i][j + 1])] = true;
                }
                if (i - 1 >= 0 && !edge[f(arr[i][j]),f(arr[i - 1][j])]) 
                {
                    gr[f(arr[i][j])].Add(f(arr[i - 1][j]));
                    edge[f(arr[i][j]), f(arr[i - 1][j])] = true;
                }
            }
  
        // Queue to perform BFS
        Queue<int> q = new Queue<int>();
        q.Enqueue(arr[0][0] - 'a');
  
        // Visited array
        bool[] v = new bool[MAX];
  
        // To store the depth of BFS
        int d = 0;
  
        // BFS
        while (q.Count > 0)
        {
  
            // Number of elements in
            // the current level
            int cnt = q.Count;
  
            // Inner loop
            while (cnt-- > 0)
            {
  
                // Current element
                int curr = q.Peek();
  
                // Popping queue
                q.Dequeue();
  
                // If the current node has
                // already been visited
                if (v[curr])
                    continue;
                v[curr] = true;
  
                // Checking if the current
                // node is the required node
                if (curr == arr[n - 1][m - 1] - 'a')
                    return d;
  
                // Iterating through the current node
                foreach (int it in gr[curr])
                    q.Enqueue(it);
            }
  
            // Updating the depth
            d++;
        }
  
        return -1;
    }
  
    // Driver code
    public static void Main(String[] args) 
    {
        String[] arr = { "abc", "def", "gbi" };
  
        Console.Write(findMinCost(arr));
    }
}
  
// This code is contributed by 29AjayKumar

chevron_right


Output:

2

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.




My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.