Open In App

Minimize steps for Knight to collect maximum points (Knight in Geekland)

Last Updated : 07 Feb, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

In Geekland, a knight is positioned at coordinates (start_x, start_y) within an N x M matrix. Each cell in the matrix contains a certain number of points. The knight has a unique ability to collect all the points from cells that can be reached in exactly i steps without revisiting any cell. Additionally, the knight possesses magical powers, allowing it to fetch points from future steps. If the knight can collect y points in the xth step, it can also fetch all the points it will collect in the (x + y)th step, and so on.

For instance, if the knight can collect 1 point in the 1st step, it will also collect all points at the 2nd step (1+1), and if it can collect 3 points in the (1+1)th step, it will also fetch all points at the (1+1+3)th step. Therefore, even at the 1st step, the knight can collect an overall total of 1+3=4 points if there are no points available at the (1+1+3)th step.

The task is to determine the minimum number of steps required for the knight to collect the maximum possible points. The knight moves exactly like a chessboard knight, following 0 indexing.

Note: The knight can move in an L-shaped pattern, similar to a knight’s movement in chess.

Example:

Input: n = 9, m = 10, start_x = 4, start_y = 5,
arr = {
{0, 0, 0, 2, 0, 2, 0, 2, 0, 0},
{0, 0, 2, 0, 2, 0, 2, 0, 2, 0},
{0, 2, 0, 0, 1, 2, 0, 0, 0, 2},
{0, 0, 2, 0, 2, 0, 2, 0, 2, 0},
{0, 2, 0, 2, 0, 0, 0, 2, 0, 2},
{0, 0, 2, 0, 2, 0, 2, 0, 2, 0},
{0, 2, 0, 0, 0, 2, 0, 0, 0, 2},
{0, 0, 2, 0, 2, 0, 2, 0, 2, 0},
{0, 0, 0, 2, 0, 2, 0, 2, 0, 0} };
Output: 1

Input: int n2 = 3, m2 = 3, start_x2 = 2, start_y2 = 1;
arr =
{7, 6, 8},
{9, 1, 4},
{6, 2, 8} };
Output: 0

Recommended Practice

Approach:

The idea is to use a Breadth-First Search (BFS) Algorithm to explore the grid. It maintains a queue of cells to visit, starting with the knight’s initial position. For each cell, it calculates the points that can be collected from that cell and updates the total points.

The BFS algorithm will continues until all cells have been visited. The points from each cell are added to the total points, and if the points from a cell plus its index is less than the size of the grid, the points are added again.

Finally, iterates over the points collected at each step and returns the index of the step that collected the maximum points..

Steps-by-step approach:

  • Perform a breadth-first search (BFS) starting from the given position of the knight.
  • At each step, calculate the score by adding the points in the current cell to the total points.
  • Update the visited matrix to mark the current cell as visited.
  • Explore all possible moves of the knight in L-shaped patterns, ensuring the moves are within the grid boundaries and the cells are not revisited.
  • Continue BFS until all reachable cells are visited and accumulate the scores at each level.
  • Iterate backward through the list of scores and update each score by adding the score at the next position.
  • Find the maximum score and its corresponding position.
  • Return the position as the minimum number of steps required to collect the maximum points.

Below is the implementation of the above approach:

C++




#include <iostream>
#include <queue>
#include <vector>
  
using namespace std;
  
// Function to find the maximum score starting from the
// given position
int knightInGeekland(int start_x, int start_y,
                     vector<vector<int> >& arr)
{
    int n = arr.size(); // number of rows
    int m = arr[0].size(); // number of columns
  
    vector<vector<int> > vis(
        n,
        vector<int>(m)); // create a visited matrix to keep
                         // track of visited positions
    vis[start_x][start_y]
        = 1; // mark the starting position as visited
    queue<pair<int, int> >
        q; // create a queue to perform breadth-first search
    q.push({ start_x, start_y }); // push the starting
                                  // position into the queue
  
    vector<int> list; // create a list to store the score
                      // obtained at each level
    int points = 0; // initialize the points to 0
  
    int dx[8] = {
        -2, -1, 1, 2, 2, 1, -1, -2
    }; // array to store possible x-direction moves
    int dy[8] = {
        1, 2, 2, 1, -1, -2, -2, -1
    }; // array to store possible y-direction moves
  
    // Helper function to check if the given position is
    // safe or not
    auto isSafe = [&](int i, int j) {
        return (i >= 0 and j >= 0 and i < n
                and j < m); // returns true if the position
                            // is within the matrix bounds
    };
  
    while (q.size()) { // while the queue is not empty
  
        int size
            = q.size(); // get the current size of the queue
  
        points = 0; // reset the points for each level
  
        for (int i = 0; i < size;
             i++) { // process all the elements in the
                    // current level
            auto tmp = q.front(); // get the front element
            q.pop(); // remove the front element from the
                     // queue
            int x = tmp.first,
                y
                = tmp.second; // get the x and y coordinates
  
            points
                += arr[x]
                      [y]; // add the score at the current
                           // position to the points
  
            // check all possible moves from the current
            // position
            for (int k = 0; k < 8; k++) {
                int xi
                    = x + dx[k]; // get the new x coordinate
                int xj
                    = y + dy[k]; // get the new y coordinate
  
                // if the new position is safe and not
                // visited, mark it as visited and push it
                // into the queue
                if (isSafe(xi, xj) && !vis[xi][xj]) {
                    vis[xi][xj] = 1; // mark the new
                                     // position as visited
                    q.push({ xi,
                             xj }); // push the new position
                                    // into the queue
                }
            }
        }
        list.push_back(
            points); // add the points obtained at the
                     // current level to the list
    }
  
    int max = -1,
        ans = -1; // variables to store the maximum score
                  // and the answer position
  
    // iterate backward through the list
    for (int i = list.size() - 1; i >= 0; i--) {
  
        // if the next position is within the list bounds,
        // add it to the current score
        if (list[i] + i < list.size())
            list[i] += list[i + list[i]];
    }
  
    // find the maximum score and its position
    for (int i = 0; i < list.size(); i++) {
        if (list[i] > max) {
            max = list[i]; // update the maximum score
            ans = i; // update the answer position
        }
    }
    return ans; // return the answer position
}
  
int main()
{
    // Provided input
    int n = 9, m = 10;
    int start_x = 4, start_y = 5;
    vector<vector<int> > arr
        = { { 0, 0, 0, 2, 0, 2, 0, 2, 0, 0 },
            { 0, 0, 2, 0, 2, 0, 2, 0, 2, 0 },
            { 0, 2, 0, 0, 1, 2, 0, 0, 0, 2 },
            { 0, 0, 2, 0, 2, 0, 2, 0, 2, 0 },
            { 0, 2, 0, 2, 0, 0, 0, 2, 0, 2 },
            { 0, 0, 2, 0, 2, 0, 2, 0, 2, 0 },
            { 0, 2, 0, 0, 0, 2, 0, 0, 0, 2 },
            { 0, 0, 2, 0, 2, 0, 2, 0, 2, 0 },
            { 0, 0, 0, 2, 0, 2, 0, 2, 0, 0 } };
  
    // Call the knightInGeekland function with the provided
    // input
    int result = knightInGeekland(start_x, start_y, arr);
  
    // Output the result
    cout << "The maximum score starting from the given "
            "position is: "
         << result << endl;
  
    return 0;
}


Java




import java.util.*;
import java.util.function.Predicate;
  
public class KnightInGeekland {
  
    // Function to find the maximum score starting from the
    // given position
    public static int
    knightInGeekland(int start_x, int start_y, int[][] arr)
    {
        int n = arr.length; // number of rows
        int m = arr[0].length; // number of columns
  
        int[][] vis
            = new int[n]
                     [m]; // create a visited matrix to keep
                          // track of visited positions
        vis[start_x][start_y]
            = 1; // mark the starting position as visited
        Queue<int[]> q
            = new LinkedList<>(); // create a queue to
                                  // perform breadth-first
                                  // search
        q.add(new int[] {
            start_x, start_y }); // push the starting
                                 // position into the queue
  
        List<Integer> list
            = new ArrayList<>(); // create a list to store
                                 // the score obtained at
                                 // each level
        int points = 0; // initialize the points to 0
  
        int[] dx = {
            -2, -1, 1, 2, 2, 1, -1, -2
        }; // array to store possible x-direction moves
        int[] dy = {
            1, 2, 2, 1, -1, -2, -2, -1
        }; // array to store possible y-direction moves
  
        // Helper function to check if the given position is
        // safe or not
        Predicate<int[]> isSafe = (pos)
            -> pos[0] >= 0 && pos[1] >= 0 && pos[0] < n
                   && pos[1] < m;
  
        while (
            !q.isEmpty()) { // while the queue is not empty
  
            int size = q.size(); // get the current size of
                                 // the queue
            points = 0; // reset the points for each level
  
            for (int i = 0; i < size;
                 i++) { // process all the elements in the
                        // current level
                int[] tmp
                    = q.poll(); // get the front element
                int x = tmp[0],
                    y
                    = tmp[1]; // get the x and y coordinates
  
                points += arr[x][y]; // add the score at the
                                     // current position to
                                     // the points
  
                // check all possible moves from the current
                // position
                for (int k = 0; k < 8; k++) {
                    int xi = x + dx[k]; // get the new x
                                        // coordinate
                    int xj = y + dy[k]; // get the new y
                                        // coordinate
  
                    // if the new position is safe and not
                    // visited, mark it as visited and push
                    // it into the queue
                    if (isSafe.test(new int[] { xi, xj })
                        && vis[xi][xj] == 0) {
                        vis[xi][xj]
                            = 1; // mark the new position as
                                 // visited
                        q.add(new int[] {
                            xi,
                            xj }); // push the new position
                                   // into the queue
                    }
                }
            }
            list.add(
                points); // add the points obtained at the
                         // current level to the list
        }
  
        int max = -1,
            ans = -1; // variables to store the maximum
                      // score and the answer position
  
        // iterate backward through the list
        for (int i = list.size() - 1; i >= 0; i--) {
            if (list.get(i) + i < list.size()) {
                list.set(i,
                         list.get(i)
                             + list.get(i + list.get(i)));
            }
        }
  
        // find the maximum score and its position
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i) > max) {
                max = list.get(
                    i); // update the maximum score
                ans = i; // update the answer position
            }
        }
        return ans; // return the answer position
    }
  
    public static void main(String[] args)
    {
        // Provided input
        int n = 9, m = 10;
        int start_x = 4, start_y = 5;
        int[][] arr = { { 0, 0, 0, 2, 0, 2, 0, 2, 0, 0 },
                        { 0, 0, 2, 0, 2, 0, 2, 0, 2, 0 },
                        { 0, 2, 0, 0, 1, 2, 0, 0, 0, 2 },
                        { 0, 0, 2, 0, 2, 0, 2, 0, 2, 0 },
                        { 0, 2, 0, 2, 0, 0, 0, 2, 0, 2 },
                        { 0, 0, 2, 0, 2, 0, 2, 0, 2, 0 },
                        { 0, 2, 0, 0, 0, 2, 0, 0, 0, 2 },
                        { 0, 0, 2, 0, 2, 0, 2, 0, 2, 0 },
                        { 0, 0, 0, 2, 0, 2, 0, 2, 0, 0 } };
  
        // Call the knightInGeekland function with the
        // provided input
        int result
            = knightInGeekland(start_x, start_y, arr);
  
        // Output the result
        System.out.println(
            "The maximum score starting from the given position is: "
            + result);
    }
}


Python3




# Python program for the above approach
from collections import deque
  
# Function to find the maximum score starting from the given position
def knight_in_geekland(start_x, start_y, arr):
    n = len(arr)  # number of rows
    m = len(arr[0])  # number of columns
  
    vis = [[0] * m for _ in range(n)]  # create a visited matrix to keep track of visited positions
    vis[start_x][start_y] = 1  # mark the starting position as visited
  
    q = deque([(start_x, start_y)])  # create a queue to perform breadth-first search
    list_points = []  # create a list to store the score obtained at each level
    points = 0  # initialize the points to 0
  
    dx = [-2, -1, 1, 2, 2, 1, -1, -2# array to store possible x-direction moves
    dy = [1, 2, 2, 1, -1, -2, -2, -1# array to store possible y-direction moves
  
    # Helper function to check if the given position is safe or not
    def is_safe(i, j):
        return 0 <= i and i < n and 0 <= j and j < m  # returns true if the position is within the matrix bounds
  
    while q:  # while the queue is not empty
        size = len(q)  # get the current size of the queue
        points = 0  # reset the points for each level
  
        for _ in range(size):  # process all the elements in the current level
            x, y = q.popleft()  # get the front element
            points += arr[x][y]  # add the score at the current position to the points
  
            # check all possible moves from the current position
            for k in range(8):
                xi, xj = x + dx[k], y + dy[k]  # get the new x and y coordinates
  
                # if the new position is safe and not visited, mark it as visited and push it into the queue
                if is_safe(xi, xj) and not vis[xi][xj]:
                    vis[xi][xj] = 1  # mark the new position as visited
                    q.append((xi, xj))  # push the new position into the queue
  
        list_points.append(points)  # add the points obtained at the current level to the list
      
    mx = -1
    ans = -1  # variable to store the answer position
  
    # iterate backward through the list
    for i in range(len(list_points) - 1, -1, -1):
        # if the next position is within the list bounds,
        # add it to the current score
        if list_points[i] + i < len(list_points):
            list_points[i] += list_points[i + list_points[i]]
  
    # find the maximum score and its position
    for i in range(len(list_points)):
        if list_points[i] > mx:
              mx = list_points[i] # update the maximum score
              ans = # update the answer position
              
    return ans  # return the answer position
  
  
# Provided input
n, m = 9, 10
start_x, start_y = 4, 5
arr = [
    [0, 0, 0, 2, 0, 2, 0, 2, 0, 0],
    [0, 0, 2, 0, 2, 0, 2, 0, 2, 0],
    [0, 2, 0, 0, 1, 2, 0, 0, 0, 2],
    [0, 0, 2, 0, 2, 0, 2, 0, 2, 0],
    [0, 2, 0, 2, 0, 0, 0, 2, 0, 2],
    [0, 0, 2, 0, 2, 0, 2, 0, 2, 0],
    [0, 2, 0, 0, 0, 2, 0, 0, 0, 2],
    [0, 0, 2, 0, 2, 0, 2, 0, 2, 0],
    [0, 0, 0, 2, 0, 2, 0, 2, 0, 0]
]
  
# Call the knight_in_geekland function with the provided input
result = knight_in_geekland(start_x, start_y, arr)
  
# Output the result
print("The maximum score starting from the given position is:", result)
  
# This code is contributed by Susobhan Akhuli


C#




// C# program for the above approach
using System;
using System.Collections.Generic;
  
public class GFG {
    // Function to find the maximum score starting from the
    // given position
    static int KnightInGeekland(int start_x, int start_y,
                                List<List<int> > arr)
    {
        int n = arr.Count; // number of rows
        int m = arr[0].Count; // number of columns
  
        List<List<int> > vis = new List<List<int> >(n);
        for (int i = 0; i < n; i++) {
            vis.Add(new List<int>(m));
            for (int j = 0; j < m; j++) {
                vis[i].Add(
                    0); // create a visited matrix to keep
                        // track of visited positions
            }
        }
  
        vis[start_x][start_y]
            = 1; // mark the starting position as visited
        Queue<Tuple<int, int> > q = new Queue<Tuple<
            int, int> >(); // create a queue to perform
                           // breadth-first search
        q.Enqueue(new Tuple<int, int>(
            start_x,
            start_y)); // enqueue the starting position
  
        List<int> list
            = new List<int>(); // create a list to store the
                               // score obtained at each
                               // level
        int points = 0; // initialize the points to 0
  
        int[] dx = {
            -2, -1, 1, 2, 2, 1, -1, -2
        }; // array to store possible x-direction moves
        int[] dy = {
            1, 2, 2, 1, -1, -2, -2, -1
        }; // array to store possible y-direction moves
  
        // Helper function to check if the given position is
        // safe or not
        Func<int, int, bool> isSafe = (i, j) => i >= 0 && j >= 0 && i < n && j < m;
  
        while (q.Count > 0) // while the queue is not empty
        {
            int size = q.Count; // get the current size of
                                // the queue
            points = 0; // reset the points for each level
  
            for (int i = 0; i < size;
                 i++) // process all the elements in the
                      // current level
            {
                Tuple<int, int> tmp
                    = q.Dequeue(); // get the front element
                int x = tmp.Item1,
                    y = tmp.Item2; // get the x and y
                                   // coordinates
  
                points += arr[x][y]; // add the score at the
                                     // current position to
                                     // the points
  
                // check all possible moves from the current
                // position
                for (int k = 0; k < 8; k++) {
                    int xi = x + dx[k]; // get the new x
                                        // coordinate
                    int xj = y + dy[k]; // get the new y
                                        // coordinate
  
                    // if the new position is safe and not
                    // visited, mark it as visited and
                    // enqueue it
                    if (isSafe(xi, xj)
                        && vis[xi][xj] == 0) {
                        vis[xi][xj]
                            = 1; // mark the new position as
                                 // visited
                        q.Enqueue(new Tuple<int, int>(
                            xi, xj)); // enqueue the new
                                      // position
                    }
                }
            }
            list.Add(
                points); // add the points obtained at the
                         // current level to the list
        }
  
        int max = -1,
            ans = -1; // variables to store the maximum
                      // score and the answer position
  
        // iterate backward through the list
        for (int i = list.Count - 1; i >= 0; i--) {
            // if the next position is within the list
            // bounds, add it to the current score
            if (list[i] + i < list.Count)
                list[i] += list[i + list[i]];
        }
  
        // find the maximum score and its position
        for (int i = 0; i < list.Count; i++) {
            if (list[i] > max) {
                max = list[i]; // update the maximum score
                ans = i; // update the answer position
            }
        }
        return ans; // return the answer position
    }
  
    static void Main()
    {
        // Provided input
        // int n = 9, m = 10;
        int start_x = 4, start_y = 5;
        List<List<int> > arr = new List<List<int> >{
            new List<int>{ 0, 0, 0, 2, 0, 2, 0, 2, 0, 0 },
            new List<int>{ 0, 0, 2, 0, 2, 0, 2, 0, 2, 0 },
            new List<int>{ 0, 2, 0, 0, 1, 2, 0, 0, 0, 2 },
            new List<int>{ 0, 0, 2, 0, 2, 0, 2, 0, 2, 0 },
            new List<int>{ 0, 2, 0, 2, 0, 0, 0, 2, 0, 2 },
            new List<int>{ 0, 0, 2, 0, 2, 0, 2, 0, 2, 0 },
            new List<int>{ 0, 2, 0, 0, 0, 2, 0, 0, 0, 2 },
            new List<int>{ 0, 0, 2, 0, 2, 0, 2, 0, 2, 0 },
            new List<int>{ 0, 0, 0, 2, 0, 2, 0, 2, 0, 0 }
        };
  
        // Call the KnightInGeekland function with the
        // provided input
        int result
            = KnightInGeekland(start_x, start_y, arr);
  
        // Output the result
        Console.WriteLine(
            "The maximum score starting from the given position is: "
            + result);
    }
}
  
// This code is contributed by Susobhan Akhuli


Javascript




// JavaScript equivalent of the given Java code
  
// Function to find the maximum score starting from the given position
function knightInGeekland(start_x, start_y, arr) {
    const n = arr.length; // number of rows
    const m = arr[0].length; // number of columns
  
    const vis = Array.from({ length: n }, () => Array(m).fill(0)); // create a visited matrix to keep track of visited positions
    vis[start_x][start_y] = 1; // mark the starting position as visited
  
    const q = []; // create a queue to perform breadth-first search
    q.push([start_x, start_y]); // push the starting position into the queue
  
    const list = []; // create a list to store the score obtained at each level
    let points = 0; // initialize the points to 0
  
    const dx = [-2, -1, 1, 2, 2, 1, -1, -2]; // array to store possible x-direction moves
    const dy = [1, 2, 2, 1, -1, -2, -2, -1]; // array to store possible y-direction moves
  
    // Helper function to check if the given position is safe or not
    const isSafe = (pos) => pos[0] >= 0 && pos[1] >= 0 && pos[0] < n && pos[1] < m;
  
    while (q.length > 0) { // while the queue is not empty
        const size = q.length; // get the current size of the queue
        points = 0; // reset the points for each level
  
        for (let i = 0; i < size; i++) { // process all the elements in the current level
            const tmp = q.shift(); // get the front element
            const x = tmp[0], y = tmp[1]; // get the x and y coordinates
  
            points += arr[x][y]; // add the score at the current position to the points
  
            // check all possible moves from the current position
            for (let k = 0; k < 8; k++) {
                const xi = x + dx[k]; // get the new x coordinate
                const xj = y + dy[k]; // get the new y coordinate
  
                // if the new position is safe and not visited, mark it as visited and push it into the queue
                if (isSafe([xi, xj]) && vis[xi][xj] === 0) {
                    vis[xi][xj] = 1; // mark the new position as visited
                    q.push([xi, xj]); // push the new position into the queue
                }
            }
        }
        list.push(points); // add the points obtained at the current level to the list
    }
  
    // iterate backward through the list
    for (let i = list.length - 1; i >= 0; i--) {
        if (list[i] + i < list.length) {
            list[i] += list[i + list[i]];
        }
    }
  
    let max = -1, ans = -1; // variables to store the maximum score and the answer position
  
    // find the maximum score and its position
    for (let i = 0; i < list.length; i++) {
        if (list[i] > max) {
            max = list[i]; // update the maximum score
            ans = i; // update the answer position
        }
    }
    return ans; // return the answer position
}
  
// Provided input
const n = 9, m = 10;
const start_x = 4, start_y = 5;
const arr = [
    [0, 0, 0, 2, 0, 2, 0, 2, 0, 0],
    [0, 0, 2, 0, 2, 0, 2, 0, 2, 0],
    [0, 2, 0, 0, 1, 2, 0, 0, 0, 2],
    [0, 0, 2, 0, 2, 0, 2, 0, 2, 0],
    [0, 2, 0, 2, 0, 0, 0, 2, 0, 2],
    [0, 0, 2, 0, 2, 0, 2, 0, 2, 0],
    [0, 2, 0, 0, 0, 2, 0, 0, 0, 2],
    [0, 0, 2, 0, 2, 0, 2, 0, 2, 0],
    [0, 0, 0, 2, 0, 2, 0, 2, 0, 0]
];
  
// Call the knightInGeekland function with the provided input
const result = knightInGeekland(start_x, start_y, arr);
  
// Output the result
console.log("The maximum score starting from the given position is: " + result);


Output

The maximum score starting from the given position is: 1


Time Complexity: O(N*M) The breadth-first search (BFS) explores each cell at most once, where N is the number of rows and M is the number of columns in the grid.
Auxiliary Space: O(N*M)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads