Algorithms, Blockchain and Cloud

Teaching Kids Programming – Multi-source Breadth First Search Algorithm (Minimum Number of Moves to Capture the King)


Teaching Kids Programming: Videos on Data Structures and Algorithms

You are given a two-dimensional integer matrix board containing 0s, 1s and 2s representing some n x n chessboard. Each 0 represents an empty cell, 1 represents the knight and 2 represents the king. There is at least one knight but exactly one king.

Given that the king stays still, return the minimum number of moves it would take for some knight to land on the king. If there’s no solution, return -1. A knight can’t land on another knight.

Constraints
2 ≤ n ≤ 500 where n is the number of rows and columns in board
1 ≤ t < n * n where t is the number of knights
k = 1 where k is the number of kings.

Example 1
Input

board = [
    [1, 0, 0, 0, 0],
    [0, 0, 0, 0, 0],
    [0, 0, 0, 0, 2],
    [1, 0, 0, 0, 0],
    [0, 0, 0, 0, 0]
]

Output
2

Explanation
The knight on top left corner can jump twice to land on the king.

Example 2
Input

board = [
    [1, 2],
    [1, 1]
]

Output
-1
Explanation
There is no way to land on the king here.

Try Traversing all the knights simultaneously.
Start with king.
Don’t let a knight touch the square touched by another knight. A knight is a knight and if one has been there before no need for others to follow in its footsteps and give less optimal solution.

Multi-source Breadth First Search Algorithm (Minimum Number of Moves to Capture the King)

We have multiple Knights and we can append them to the queue initially which is the essential of multi-source Breadth First Search Algorithm. Assuming N positions in the board, and the number of maximum edges are (we can visualize the Board as undirectional Graph, each position is a vertex and each valid move forms an edge):

which is

Note that the actual number of edges is way smaller considering invalid edges such as the Knight traverses in a shape of offset (1, 2), (2, 1) …

For a knight, next move could be maximum 8 positions if those are still valid within the board. If a position is occupied with another knight, there is no point in pushing it to the queue as it will be always quicker to start from that knight instead.

class Solution:
    def solve(self, board):
        EMPTY = 0
        KNIGHT = 1
        KING = 2

        rows = len(board)
        cols = len(board[0])

        q = deque()
        for r in range(rows):
            for c in range(cols):
                if board[r][c] == KNIGHT:
                    q.append((r, c))

        ans = -1
        seen = set()
        while q:
            ans += 1
            n = len(q)
            for _ in range(n):
                r, c = q.popleft()
                if board[r][c] == KING:
                    return ans
                for dr, dc in ((1, -2), (1, 2), (2, -1), (2, 1), (2, -1), \
                                (-1, 2), (-1, -2), (-2, 1), (-2, -1)):
                    nr, nc = r + dr, c + dc
                    if 0 <= nr < rows and 0 <= nc < cols and (nr, nc) not in seen\
                        and board[nr][nc] != KNIGHT:
                        seen.add((nr, nc))
                        q.append((nr, nc))

        return -1

The space complexity is O(N) as we are using a hash set to remember the positions that we have visited and also we use a queue (aka deque) to implement the multi-source Breadth First Search Algorithm.

The time complexity is where M is the number of the knights, and since the time complexity is .

There is only 1 king i.e. the number of Kings is smaller than the number of Knights, and thus we can reverse the process, start the search from the King instead:

class Solution:
    def solve(self, board):
        EMPTY = 0
        KNIGHT = 1
        KING = 2

        rows = len(board)
        cols = len(board[0])

        q = deque()
        for r in range(rows):
            for c in range(cols):
                if board[r][c] == KING:
                    q.append((r, c))
                    # if there is only 1 king - we can break here
                    break

        ans = -1
        seen = set()
        while q:
            ans += 1
            n = len(q)
            for _ in range(n):
                r, c = q.popleft()
                if board[r][c] == KNIGHT:
                    return ans
                for dr, dc in ((1, -2), (1, 2), (2, -1), (2, 1), (2, -1), \
                                (-1, 2), (-1, -2), (-2, 1), (-2, -1)):
                    nr, nc = r + dr, c + dc
                    if 0 <= nr < rows and 0 <= nc < cols and (nr, nc) not in seen:
                        seen.add((nr, nc))
                        q.append((nr, nc))

        return -1

The time complexity is as we at most visit each edge once. The space complexity is O(N).

–EOF (The Ultimate Computing & Technology Blog) —

1033 words
Last Post: Teaching Kids Programming - Remove Last Duplicate Entries (Hash Table)
Next Post: Teaching Kids Programming - Maximum Depth of N-ary Tree via Depth First Search or Breadth First Search Algorithms

The Permanent URL is: Teaching Kids Programming – Multi-source Breadth First Search Algorithm (Minimum Number of Moves to Capture the King) (AMP Version)

Exit mobile version