ナイトが目標に到達するための最小ステップ


難易度 ハード
よく聞かれる Amazon (アマゾン) LinkedIn MakeMyTrip
幅優先探索 動的計画法 グラフ キュー

説明

「ナイトがターゲットに到達するための最小ステップ」の問題は、N x Nの寸法の正方形のチェス盤、ナイトピースの座標、およびターゲットセルが与えられることを示しています。 ナイトピースがターゲットセルに到達するために取る最小ステップ数を調べます。

ナイトステップ:チェスのルールに従って、騎士は一方向に2マス、垂直方向に1マス移動します(またはその逆)。

(kx,ky) = (1,1) & (tx,ty) = (15,15)
Minimum number of moves = 10
(kx,ky) = (2,8) & (tx,ty) = (8,4)
Minimum number of moves = 4
(kx,ky) = (2,8) & (tx,ty) = (8,4)
Minimum number of moves = 4

ナイトが目標に到達するための最小ステップ

 

ソリューションの種類

  1. 幅優先探索

  2. 動的計画法

幅優先探索

アプローチ

アイデアは実行することです BFS 騎士の初期位置から始まります。 次のすべてのセル(およびその次のセル)に、指定された位置(または座標)から繰り返し進みます。次の各セルは、 ナイトステップ マナー。 トラバーサルはBFSキューを使用して実行されます。 各キューノード BFSトラバーサル中に出会ったセルの座標と、その特定のセルに到達するために実行されたステップ数を格納します。 ターゲットセルがBFSキューからポップされると、ステップ数の値が必要な答えになります。

アルゴリズム

1. Define a class that has following data variables:
    1. x: to store x-coordinate of the cell.
    2. y: to store y-coordinate of the cell.
    3. steps: number of steps required to reach that cell starting from co-ordinates of the Knight.
2. Create a BFS queue that stores class objects as nodes.
3. Begin the Iterative BFS traversal.
4. In every step of the iterative traversal, pop a node from the queue. say,the node is front.
5. If the cell at coordinates (front.y, front.x) is the target cell, return the value of front.steps.
    1. Else, continue the iterative traversal.

ナイトが目標に到達するための最小ステップ

ナイトが目標に到達するための最小ステップ

コード

ナイトが目標に到達するための最小ステップを見つけるためのC ++プログラム

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

// definition of queue node
class Node
{
    public:
    // y-coordinate
    int y;
    // x-coordinate
    int x;
    // number of steps to reach (y,x)
    int steps;
    
    // constructor
    Node(int i,int j,int moves)
    {
        y = i;
        x = j;
        steps = moves;
    }
};

// traversal array along rows
int dx[] = {-2, -1, 1, 2, -2, -1, 1, 2};
// traversal array along columns
int dy[] = {-1, -2, -2, -1, 1, 2, 2, 1}; 

// BFS to return number of steps required to reach from source to target
int BFS(Node source, Node target, int N)
{
    // set to mark a cell as visited
    unordered_set <string> visited;
    // BFS queue
    queue <Node> q;
    // push the source node
    q.push(source);
    
    // BFS traversal 
    while(!q.empty())
    {
        Node front = q.front();
        q.pop(); 
        
        // if target coordinate is reached
        if(front.y == target.y && front.x == target.x)
        return front.steps;
        
        // traverse all neighbors of current cell
        for(int i=0;i<8;i++)
        {
            int next_y = front.y + dy[i];
            int next_x = front.x + dx[i];
            
            // store coordinates of a cell as string
            string search = to_string(next_y) + '|' + to_string(next_x);
            
            // move to neighbor cell if it is not visited lies within the N x N chessboard
            if(visited.find(search) == visited.end() && next_y > 0 && next_x > 0 && next_y <= N && next_x <= N)
            {
                Node next(next_y,next_x,front.steps+1);
                q.push(next);
                visited.insert(search);
            }
        }
    }
}

int main()
{
    // dimensions of the square chessboard
    int N = 8;
    // coordinates of source & target cell
    Node source(2,8,0), target(8,4,-1);
    cout<<"Number of steps : "<<BFS(source,target,N)<<endl;
    return 0;
}
Number of steps : 4

ナイトが目標に到達するための最小ステップを見つけるJavaプログラム

import java.util.*;
import java.io.*;

class TutorialCup 
{
    // definition of queue node
    static class Node
    {
        // y-coordinate
        int y;
        // x-coordinate
        int x;
        // number of steps to reach (y,x)
        int steps;
        
        // constructor
        Node(int i,int j,int moves)
        {
            y = i;
            x = j;
            steps = moves;
        }
    };
    
    // traversal array along rows
    static int dx[] = {-2, -1, 1, 2, -2, -1, 1, 2};
    // traversal array along columns
    static int dy[] = {-1, -2, -2, -1, 1, 2, 2, 1}; 
    
    // BFS to return number of steps required to reach from source to target
    static int BFS(Node source, Node target, int N)
    {
        // set to mark a cell as visited
        HashSet <String> visited = new HashSet<>();
        // BFS queue
        Queue <Node> q = new LinkedList<>();
        // push the source node
        q.add(source);
        
        // BFS traversal 
        while(!q.isEmpty())
        {
            Node front = q.poll();
            
            // if target coordinate is reached
            if(front.y == target.y && front.x == target.x)
            return front.steps;
            
            // traverse all neighbors of current cell
            for(int i=0;i<8;i++)
            {
                int next_y = front.y + dy[i];
                int next_x = front.x + dx[i];
                
                // store coordinates of a cell as string
                String search = next_y + "|" + next_x;
                
                // move to neighbor cell if it is not visited lies within the N x N chessboard
                if(visited.contains(search) == false && next_y > 0 && next_x > 0 && next_y <= N && next_x <= N)
                {
                    Node next = new Node(next_y,next_x,front.steps+1);
                    q.add(next);
                    visited.add(search);
                }
            }
        }
        return 0;
    }
    public static void main (String[] args)
    {
        // dimensions of the square chessboard
        int N = 8;
        // coordinates of source & target cell
        Node source = new Node(2,8,0);
        Node target = new Node(8,4,-1);
        System.out.println("Number of steps : "+BFS(source,target,N));
    }
}
Number of steps : 4

複雑さの分析

  1. 時間計算量:T(n)= O(N ^ 2)
    正方行列があり、最悪の場合です。 したがって、各セルを処理する必要がある場合があります。 そして、それが二次時間計算量が達成される方法です。
  2. スペースの複雑さ:A(n)= O(N ^ 2)
    ここではBFSを使用しました。そのため、アルゴリズムには多項式空間の複雑さがあります。

動的計画法

アプローチ

問題のアプローチを理解するには、以下の点を考慮してください。

以下の仮定を考慮してください。

  1. チェス盤は標準のNxNの正方形です。
  2. kxとkyは騎士の座標です。
  3. txとtyは、ターゲットセルの座標です。

 

非線形位置 :ナイトとターゲットセルが異なる行と列に沿っている場合。 すなわちkx not = tx&ky not = TY。

  1. 例:(kx、ky)=(3,3)&(tx、ty)=(6,6)
  2. 次の2つのステップだけがターゲットに向かって移動します。
    • (3,3)->(4,5)および(3,3)->(5,4)
  3. したがって、 動的計画法, minSteps {(3,3)to(6,6)} = 1 + [minSteps {(4,5)to(6,6)} or minSteps {(5,4)to(6,6)}]

ナイトが目標に到達するための最小ステップ

線形位置 :ナイトとターゲットセルが同じ行または列に沿っている場合。 すなわちどちらか kx = tx or ky = ty.

  1. 例:(kx、ky)=(2,4)&(tx、ty)=(7,4)
  2. ターゲットに向かって移動するステップは全部で4つあり、次のとおりです。
    • (2,4)->(4,5)および(2,4)->(4,3)、これらのステップは両方とも同等です
    • (2,4)->(3,6)および(2,4)->(3,2)、これらのステップは両方とも同等です
  3. したがって、 動的計画法, minSteps {(2,4)to(7,4)} = 1 + [minSteps {(2,4)から(4,5)} , minSteps {(2,4)から(3,6)}].

ナイトが目標に到達するための最小ステップ

コーナーケース :ナイトまたはターゲットのいずれかがコーナーにあり、 [腹筋(kx-tx) 、abs(ky-ty)] = [1,1]。 その場合、目標に到達するための最小ステップは4になります。

次のコードスニペットは、基本ケースを示しています。

ベースケース :基本的なケースについては、以下で説明します。

次のコードスニペットは、基本ケースを示しています。

  動的計画法 集計を使用した方程式は次のようになります:

  1. table [abs(kx – tx)] [abs(ky – ty)] =騎士の位置(kx、ky)から目標位置(tx、ty)に到達するための最小ステップ数。
  2. table [abs(kx – tx)] [abs(ky – ty)] = table [abs(ky – ty)] [abs(kx – tx)]。

アルゴリズム

1. Define the solution for corner cases. i.e. when the knight or target are at 4 corners of the board and difference in their positions are (1,1). The minimum number of moves from source to target is 4. These positions are depicted below:
2. Define the base cases as discussed below:
    1. when the Knight & target are at adjacent squares (along the same row/column), minimum number of moves required to reach the destination is 3.
    2. when the Knight & target are at adjacent squares but lie diagonally to each other, minimum number of moves required to reach the destinations is 2.
    3. when Knight & target are at positions as depicted in the image, minimum number of moves required to reach destination is 1.
    4. If the Knight & target are at same position, minimum number of moves required is 0.
3. For any other case, refer Linear Positions & Non-Linear Positions in the approach section.

コード

ナイトが目標に到達するための最小ステップを見つけるためのC ++プログラム

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

int minStepsRecur(int kx, int ky, int tx, int ty, vector<vector<int>>& table) 
{ 
    // when Knight & Target are at same position
    if (kx == tx && ky == ty) 
        return table[0][0];
    
    else 
    { 
        // if value in the table has been calculated already
        if (table[abs(kx - tx)][abs(ky - ty)] != 0) 
            return table[abs(kx - tx)][abs(ky - ty)]; 
            
        // Linear Positions
        /* Knight can move to -->2 different squares<-- that goes towards the Target */
        
        // Non-Linear Positions
        /* Knight can move to 4 different squares that 
        goes towards the Target of which -->2 are equivalent<-- */
        
        // For every position of Knight & Target 
        // there are 2 different positions i.e. (x1,y1) & (x2,y2), the Knight can move to. 
        else 
        { 
  
            int x1, y1, x2, y2; 
              
            // the values of (x1,y1) & (x2,y2) depend upon relative positions of Knight & Target
            // (x1,y1) & (x2,y2) are midway between (kx,ky) & (tx,ty)
            // Their calculations are made accordingly
            if (kx <= tx) 
            { 
                if (ky <= ty) 
                { 
                    x1 = kx + 2; 
                    y1 = ky + 1; 
                    x2 = kx + 1; 
                    y2 = ky + 2; 
                } 
                else 
                { 
                    x1 = kx + 2; 
                    y1 = ky - 1; 
                    x2 = kx + 1; 
                    y2 = ky - 2; 
                } 
            } 
            
            else 
            { 
                if (ky <= ty) 
                { 
                    x1 = kx - 2; 
                    y1 = ky + 1; 
                    x2 = kx - 1; 
                    y2 = ky + 2; 
                } 
                else 
                { 
                    x1 = kx - 2; 
                    y1 = ky - 1; 
                    x2 = kx - 1; 
                    y2 = ky - 2; 
                } 
            } 
              
            // The minimum steps from (kx,ky) to (tx,ty) = 1 + minimum of steps from (x1, y1) to (x2, y2). 
            table[abs(kx - tx)][abs(ky - ty)] = 1 + min(minStepsRecur(x1, y1, tx, ty, table),minStepsRecur(x2, y2, tx, ty, table)); 
                             
            // exchanging the coordinates x with y of both knight and target will result in same min moves. 
            table[abs(ky - ty)][abs(kx - tx)] = table[abs(kx - tx)][abs(ky - ty)];
            
            return table[abs(kx - tx)][abs(ky - ty)]; 
        } 
    } 
} 

int minSteps(int kx, int ky, int tx, int ty, int n)
{
    // Corner Cases
    if ((kx == 1 && ky == 1 && tx == 2 && ty == 2) || (kx == 2 && ky == 2 && tx == 1 && ty == 1)) 
        return 4; 
    
    else if ((kx == 1 && ky == n && tx == 2 && ty == n - 1) || (kx == 2 && ky == n - 1 && tx == 1 && ty == n)) 
        return 4; 
    
    else if ((kx == n && ky == 1 && tx == n - 1 && ty == 2) || (kx == n - 1 && ky == 2 && tx == n && ty == 1)) 
        return 4; 
    
    else if ((kx == n && ky == n && tx == n - 1 && ty == n - 1) || (kx == n - 1 && ky == n - 1 && tx == n && ty == n)) 
        return 4;
    
    else 
    {
        vector <int> row(20,0);
        vector <vector<int>> table;
        

        for(int i=0; i<20; i++)
        table.push_back(row);
        
        // Base Cases
        table[2][1] = 1; 
        table[1][2] = 1; 
        
        table[1][1] = 2; 
        table[2][0] = 2; 
        table[0][2] = 2;
        
        table[1][0] = 3; 
        table[0][1] = 3; 
        
       
        // Linear & Non-Linear positions
        return minStepsRecur(kx, ky, tx, ty, table);
    } 
}

int main()
{
    int n = 8;
    int kx = 2, ky = 8, tx = 8, ty = 4;
    
    cout<<"Number of steps : "<<minSteps(kx,ky,tx,ty,n)<<endl;
    return 0;
}
Number of steps : 4

ナイトが目標に到達するための最小ステップを見つけるJavaプログラム

import java.util.*;
import java.io.*;

class TutorialCup
{
    static int minStepsRecur(int kx, int ky, int tx, int ty, int [][] table) 
    { 
        // when Knight & Target are at same position
        if (kx == tx && ky == ty) 
            return table[0][0];
        
        else 
        { 
            // if value in the table has been calculated already
            if (table[Math.abs(kx - tx)][Math.abs(ky - ty)] != 0) 
                return table[Math.abs(kx - tx)][Math.abs(ky - ty)]; 
                
            // Linear Positions
            /* Knight can move to -->2 different squares<-- that goes towards the Target */
            
            // Non-Linear Positions
            /* Knight can move to 4 different squares that 
            goes towards the Target of which -->2 are equivalent<-- */
            
            // For every position of Knight & Target 
            // there are 2 different positions i.e. (x1,y1) & (x2,y2), the Knight can move to. 
            else 
            { 
      
                int x1, y1, x2, y2; 
                  
                // the values of (x1,y1) & (x2,y2) depend upon relative positions of Knight & Target
                // (x1,y1) & (x2,y2) are midway between (kx,ky) & (tx,ty)
                // Their calculations are made accordingly
                if (kx <= tx) 
                { 
                    if (ky <= ty) 
                    { 
                        x1 = kx + 2; 
                        y1 = ky + 1; 
                        x2 = kx + 1; 
                        y2 = ky + 2; 
                    } 
                    else 
                    { 
                        x1 = kx + 2; 
                        y1 = ky - 1; 
                        x2 = kx + 1; 
                        y2 = ky - 2; 
                    } 
                } 
                
                else 
                { 
                    if (ky <= ty) 
                    { 
                        x1 = kx - 2; 
                        y1 = ky + 1; 
                        x2 = kx - 1; 
                        y2 = ky + 2; 
                    } 
                    else 
                    { 
                        x1 = kx - 2; 
                        y1 = ky - 1; 
                        x2 = kx - 1; 
                        y2 = ky - 2; 
                    } 
                } 
                  
                // The minimum steps from (kx,ky) to (tx,ty) = 1 + minimum of steps from (x1, y1) to (x2, y2). 
                table[Math.abs(kx - tx)][Math.abs(ky - ty)] = 1 + Math.min(minStepsRecur(x1, y1, tx, ty, table),minStepsRecur(x2, y2, tx, ty, table)); 
                                 
                // exchanging the coordinates x with y of both knight and target will result in same min moves. 
                table[Math.abs(ky - ty)][Math.abs(kx - tx)] = table[Math.abs(kx - tx)][Math.abs(ky - ty)];
                
                return table[Math.abs(kx - tx)][Math.abs(ky - ty)]; 
            } 
        } 
    } 

    static int minSteps(int kx, int ky, int tx, int ty, int n)
    {
        // Corner Cases
        if ((kx == 1 && ky == 1 && tx == 2 && ty == 2) || (kx == 2 && ky == 2 && tx == 1 && ty == 1)) 
            return 4; 
        
        else if ((kx == 1 && ky == n && tx == 2 && ty == n - 1) || (kx == 2 && ky == n - 1 && tx == 1 && ty == n)) 
            return 4; 
        
        else if ((kx == n && ky == 1 && tx == n - 1 && ty == 2) || (kx == n - 1 && ky == 2 && tx == n && ty == 1)) 
            return 4; 
        
        else if ((kx == n && ky == n && tx == n - 1 && ty == n - 1) || (kx == n - 1 && ky == n - 1 && tx == n && ty == n)) 
            return 4;
        
        else 
        {
            int [][] table = new int[20][20];
            
            // Base Cases
            table[2][1] = 1; 
            table[1][2] = 1; 
            
            table[1][1] = 2; 
            table[2][0] = 2; 
            table[0][2] = 2;
            
            table[1][0] = 3; 
            table[0][1] = 3; 
            
           
            // Linear & Non-Linear positions
            return minStepsRecur(kx, ky, tx, ty, table);
        } 
    }
    
    public static void main (String[] args) 
    {
        int n = 8;
        int kx = 2, ky = 8, tx = 8, ty = 4;
        
        System.out.println("Number of steps : "+minSteps(kx,ky,tx,ty,n));
    }
}
Number of steps : 4

複雑さの分析

  1. 時間の複雑さ:T(n)= O [abs( (kx-tx)*(ky-ty) )]
    開始セルと宛先セルによって形成された部分行列に含まれるセルのみを扱っているためです。 したがって、このソリューションにも上記のソリューションと同様のXNUMX次時間計算量があります。
  2. スペースの複雑さ:A(n)= O [abs( (kx-tx)*(ky-ty) )]

どこ、

  1. (kx、ky)=騎士の位置
  2. (tx、ty)=ターゲットセルの位置