Awesome Grid Problem - DSA

Awesome Grid Problem - DSA

Question

Forked !! All possible locations where a Peculiar Knight can FORK King and Queen

Problem statement

Input and Output

Time and Space Constrains

Sample Input and Output

Input
4
2 1
0 0
3 3
1 1
3 1
1 3
4 4
0 0
8 0
4 2
1 4
3 4
Output
2
1
2
0
Explanation for the given test cases

First Intuitions I had

  • More often than not Knight won't be able to fork both Queen and King. so it's a peculiar case that likely follows some rule

    • So there should be some condition that the Queen and King positions satisfy if it could be forked by Knight.
  • Since this a 2D question, I can employ this trick I always used in python, a year ago when I was doing Graphs

    • Code from -> All algorithms I wrote while I was in my second semester

      • This idea of using a dir 2d array keeping track of all possible dx and dy changes in direction.

      • In C++ ( the language I am trying to get better at, hence my profile name ) we can use a vector of pair of long long to achieve the same technique.

  • I spend half an hour thinking about what must be that condition that the positions need to follow

    • and finally got it !

Algorithm I came up with

While thinking about different possibilities, the first thing that caught my eye was that I'd have to treat 2 cases slightly differently :-

  • Normal case ( a != b ) => 8 different positions that the Knight can move to.

  • Edge case ( a == b ) => 4 different positions that the Knight can move to.

General Algorithm :-

  1. Store all possible positions a knight could have moved if it was in the position of King => ( a maximum total of 8 positions )

  2. From each of the stored positions, can a Knight reach the Queen => ( a maximum of 64 possible positions to check )

  3. Count all the possible ways we can reach from stored position to Queen

So we finish this in almost constant time, which makes this a pretty good algorithm.

Note : King and Queen can be switched in the algorithms and it would not matter. You can either from King and try to reach the Queen (or) start from Queen and try to reach the King. What is important is that IF IS IT POSSSIBLE to reach from one to another.

Visualization and Intuition

Visualization of 2d co-ordinates system as a Lattice structure ( only Integer co-ordinates ) and each point is a possible position.

I might update this blog and code an animation in Manim to show all possible points and all possible positions from each of the stored positions, why this algorithm always works. ( No promises though, I'm going to write Endsems in a week! )

In step - 1 of algorithm, we need to store all these points ( getting these points is just basic math )

$$\left( X_{pos} , Y_{pos} \right) = \left( X_K \pm a , Y_K \pm b \right)$$

$$\left( X_{pos} , Y_{pos} \right) = \left( X_K \pm b , Y_K \pm a \right)$$

These are the 8 possible positions. It's easy to see that at a == b first and second set of points yields exactly same results hence there would only be 4 distinct positions.

In step - 2 we see if :-

$$\left( X_{pos} \pm a, Y_{pos} \pm b \right) = \left( X_Q, Y_Q \right)$$

$$\left( X_{pos} \pm b, Y_{pos} \pm a \right) = \left( X_Q, Y_Q \right)$$

We see if we can get to Queen from any one of the 8 coordinates we stores in step1.

Constructing the Code to implement the Algorithm

  • Taking input and checking if it's an edge case or not.

    •             int dir_x[] = {1, 1, -1, -1}; 
                  int dir_y[] = {1, -1, 1, -1}; 
      
                  ll t,a,b,x1,y1,x2,y2; cin >> t;
      
                  while(t--){
                      int edge_case = 0;
      
                      cin >> a >> b ;
                      if(a==b)edge_case = 1;
                      cin >> x1 >> y1 ;
                      cin >> x2 >> y2 ;
                  }
      
  • Storing all possible positions from King's co-ordinates (x1,y1)

    • This snippet of code is something that I am proud of :-

    • There is a lot going in this snippet, particularly this idea of swapping and a,b for the second iteration ( when a!=b therefore not in edge case ) ; I learnt this idea from this Japanese coder Kotatsugame and his wonderful algorithms' streams.

  • Now we need to be able to count all the ways to go from each of stored positions in pos to Queen.

Complete Code

#include <iostream>
#include <vector>
#include <bits/stl_pair.h>
using namespace std;

typedef long long ll ;


void solve(){

    int dir_x[] = {1, 1, -1, -1}; 
    int dir_y[] = {1, -1, 1, -1}; 

    ll t,a,b,x1,y1,x2,y2; cin >> t;

    while(t--){
        int edge_case = 0;

        cin >> a >> b ;
        if(a==b)edge_case = 1;
        cin >> x1 >> y1 ;
        cin >> x2 >> y2 ;

        vector<pair<ll,ll>> pos;
        int n = (!edge_case) ? 2 : 1;

        for(int j=1;j<=n;j++){
            for (int i=0; i<4; i++){
                pos.push_back( make_pair( x1 + dir_x[i]*a, y1 +  dir_y[i]*b) ); 
            }swap(a,b);
        }

        n = (!edge_case) ? 8 : 4;
        int c = 0 ;

        for(int i=0;i<n;i++){
            for(int j=0; j<4; j++){
                if(pos[i].first + a*dir_x[j] == x2 && pos[i].second + b*dir_y[j] == y2 )c++;
            }

            if(!edge_case){
                swap(a,b);
                for(int j=0; j<4; j++){
                    if(pos[i].first + a*dir_x[j] == x2 && pos[i].second + b*dir_y[j] == y2 )c++;
                }
            }
        }
        cout << c << "\n";
    }
}


int main(){
    ios::sync_with_stdio(0); cin.tie(0);
    solve() ; 
}

An Optimization that I thought of while writing this post

It seems to me that there exists a maximum distance between the king and Queen, beyond which WE DON'T EVEN NEED AN ALGORITHM, it is just impossible to get from King to Queen, via 2 steps of a Knight.

Here I took, King to be at origin, but it's not hard to see that we don't lose any generality in this line argument :-

The Maximum distance between King and Queen ( denoted by D) can not exceed some limit.

$$D \le 2\sqrt{a^2 + b^2}$$

Why this is useful ?

$$if \space D > 2\sqrt{a^2+b^2} \Rightarrow Ans = 0$$

$$\sqrt{ (X_k-X_Q)^2 + (Y_k-Y_Q)^2 } > 2\sqrt{a^2+b^2}$$

If we check for this condition in the beginning we can easily say if it is possible or not without running the algorithm. We only have to run if the given points does not satisfy the condition, making the Queen be closer to the King and potentially a chance for fork could exist.

Thank you,

__CPP_Try_Hard__ ;