1064. The way a Knight

 

On a chessboard consisting of n×n cells, several of them are cut. Find the path of minimum length for a Knight from one cell to another. The Knight can’t go through cut cells.

 

Input. The first row is set to the number n (2 ≤ n ≤ 50). Each of the next n lines contains n symbols. The symbol # denotes the cut cell, the point is not a cut cell, and the symbol @ denotes the initial and final cell of the Knight’s path (the chessboard contains two such characters).

 

Output. If the path can not be constructed, print “Impossible”. Otherwise, print the same map as the input, but check all Knight intermediate positions with the symbol @.

 

Sample input

Sample output

5
@..@.
..##.
.....
.....

.....

@..@.

..##.

.@..@

..@..

@....

 

 

SOLUTION

graphs – breadth first search

 

Algorithm analysis

To solve the problem, it is enough to run a breadth-first search from one of the cells, denoted by the @ symbol. Then, using the array of ancestors, restore the shortest path, if it exists.

 

Algorithm realization

In the arrays dx and dy we describe all possible moves of the knight. From the cell (i, j) the knight can go to one of the cells (i + dx[k], j + dy[k]), 0 ≤ k ≤ 7.

 

int dx[] = {1,1,-1,-1,2,2,-2,-2};

int dy[] = {2,-2,2,-2,1,-1,1,-1};

 

Store the position of the knight on the board as a pair of coordinates (x, y). For this we declare the CELL structure. Let's declare cell comparison operators (“equal to” and “not equal to”).

 

struct CELL

{

  int x, y;

  CELL(int a = -1, int b = -1) : x(a), y(b) {};

};

 

int operator==(CELL a, CELL b)

{

  return (a.x == b.x) && (a.y == b.y);

}

 

int operator!=(CELL a, CELL b)

{

  return !((a.x == b.x) && (a.y == b.y));

}

 

Lets declare an array of ancestors Parent. An ancestor array will be used to remember the visited cells of the chessboard. If Parent[i][j] = (-1, -1), then cell (i, j) has not yet been visited by the horse. Lets define an empty cell EMPTY_CELL.

 

CELL EMPTY_CELL(-1,-1), Start(-1,-1), Finish(-1,-1);

CELL Parent[MAX][MAX];

 

The initial state of the board we read into the array s.

 

char s[MAX][MAX];

 

The function CanGo returns 1 if cell c is not outside the field boundary.

 

int CanGo(CELL c)

{

  return !((c.x < 0) || (c.x >= n) || (c.y < 0) || (c.y >= n));

}

 

The function bfs runs the breadth first search from the cell Start. Lets declare the queue d.

 

void bfs(CELL Start)

{

  deque<CELL> d;

  d.push_back(Start);

  s[Start.x][Start.y] = '#';

  while(!d.empty())

  {

 

Take the position of type Node from the head of the queue. Make all possible moves with the knight from there.

 

    CELL Node = d.front(); d.pop_front();

    for(int k = 0; k < 8; k++)

    {

      CELL Next = CELL(Node.x + dx[k], Node.y + dy[k]);

 

If the move is made to position Next, which is located outside the edges of the board, then it is impossible to make it.

 

      if (!CanGo(Next)) continue;

 

If the position Next is an uncut cell and we havent been there yet, then we go there. In the array of ancestors, we note that we got to Next from the cell Node.

 

      if ((s[Next.x][Next.y] != '#') &&

          (Parent[Next.x][Next.y] == EMPTY_CELL))

      {

        Parent[Next.x][Next.y] = Node;

 

If we came to the final vertex Finish, then we should stop the search.

 

        if (Next == Finish) return;

 

Move the cell Next to the end of the queue d.

 

        d.push_back(Next);

      }

    }

  }

}

 

The main part of the program. Perform the initialization of variables. Read the state of the chessboard into the array s. The coordinates of the initial and final positions of the knight, marked on the board with the @ symbol, are stored in the variables Start and Finish of type CELL.

 

scanf("%d\n",&n);

for(i = 0; i < n; i++) gets(s[i]);

for(i = 0; i < n; i++)

for(j = 0; j < n; j++)

  if (s[i][j] == '@')

  {

    if (Start.x == -1) {Start.x = i; Start.y = j;}

    else {Finish.x = i; Finish.y = j;}

  }

 

Start the breadth first search from the cell Start.

 

bfs(Start);

 

We could complete the breadth first search by fulfilling one of the two conditions: either all the vertices that can be reached by the knight from the cell Start were visited and the queue d became empty, or at some point in time we came to Finish and exited the bfs function.

If the depth first search does not reach the cell Finish, then the required knight path does not exist.

 

if (Parent[Finish.x][Finish.y] == EMPTY_CELL) printf("Impossible\n");

else

{

 

If the shortest path from Start to Finish exists, then using the array of ancestors, we restore it. The shortest path of the knight is filled with @ symbols.

 

  s[Start.x][Start.y] = '@';

  while(Start != Finish)

  {

    s[Finish.x][Finish.y] = '@';

    Finish = Parent[Finish.x][Finish.y];

  }

 

Print the resulting chessboard.

 

  for(i = 0; i < n; i++) puts(s[i]);

}