Given two integers, n and m, denoting dimensions of a chessboard. The task is to count ways to place a black and a white knight on an n * m chessboard such that they do not attack each other. The knights have to be placed on different squares.
Note: A knight can move two squares horizontally and one square vertically (L shaped), or two squares vertically and one square horizontally (L shaped). The knights attack each other if one can reach the other in one move.

Examples:
Input: n = 2, m = 2
Output: 12
Explanation: The first Kniight can be placed in any of the 4 cells and the second knight can be be placed in any of the remaining 3 cells. For a Knight to attack. one dimension must be at least 3.Input: n = 2, m = 3
Output: 26
Table of Content
[Naive Approach] Counting Valid Knight Moves – O(n * m) Time and O(1) Space
The idea is to count total ways to place two knights on the board and subtract the number of attacking pairs. For every cell, we calculate how many valid knight moves it can make (only in one direction set to avoid double counting).
- Total ways two knights can be placed is (n*m)*(n*m - 1) [The first one at any square and the second on at any other square)
- Traverse every cell and count valid knight moves using predefined directions
- Each valid move contributes to attacking pairs count hence attacking positions increase by 2.
- Return total pairs minus attacking pairs.
#include <iostream>
using namespace std;
// Function returns the count
// of arrangements
int numOfWays(int n, int m)
{
// A Knight can move in 8 directions, but
// we only take downward directions to avoid
// counting same positions twice
int x_axis[]{ -2, -1, 1, 2 };
int y_axis[]{ 1, 2, 2, 1 };
// Total ways to place two Knights
long long total = m * n;
total = total * (total - 1);
// Cunt attackig positions of a single
// Knight
long long ret = 0;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
for (int k = 0; k < 4; ++k) {
int x = i + x_axis[k], y = j + y_axis[k];
if (x >= 0 && x < m && y >= 0 && y < n)
// Since (i, j) and (x, y) are attacking
// positions for each other, we cannot
// place either of the two at any of these
ret += 2;
}
}
}
return total - ret;
}
// Driver code
int main()
{
int n = 2, m = 3;
cout << numOfWays(n, m) << endl;
return 0;
}
public class Main {
// Function returns the count
// of arrangements
public static int numOfWays(int n, int m)
{
// A Knight can move in 8 directions, but
// we only take downward directions to avoid
// counting same positions twice
int x_axis[] = { -2, -1, 1, 2 };
int y_axis[] = { 1, 2, 2, 1 };
// Total ways to place two Knights
long total = m * n;
total = total * (total - 1);
// Count attacking positions of a single
// Knight
long ret = 0;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
for (int k = 0; k < 4; ++k) {
int x = i + x_axis[k], y
= j + y_axis[k];
if (x >= 0 && x < m && y >= 0 && y < n)
// Since (i, j) and (x, y) are
// attacking positions for each
// other, we cannot place either of
// the two at any of these
ret += 2;
}
}
}
return (int)(total - ret);
}
// Driver code
public static void main(String[] args)
{
int n = 2, m = 3;
System.out.println(numOfWays(n, m));
}
}
def numOfWays(n, m):
# A Knight can move in 8 directions, but
# we only take downward directions to avoid
# counting same positions twice
x_axis = [-2, -1, 1, 2]
y_axis = [1, 2, 2, 1]
# Total ways to place two Knights
total = m * n
total = total * (total - 1)
# Count attacking positions of a single
# Knight
ret = 0
for i in range(m):
for j in range(n):
for k in range(4):
x = i + x_axis[k]
y = j + y_axis[k]
if x >= 0 and x < m and y >= 0 and y < n:
# Since (i, j) and (x, y) are attacking
# positions for each other, we cannot
# place either of the two at any of these
ret += 2
return total - ret
# Driver code
n = 2
m = 3
print(numOfWays(n, m))
using System;
public class Program {
// Function returns the count of arrangements
public static int numOfWays(int n, int m)
{
// A Knight can move in 8 directions, but
// we only take downward directions to avoid
// counting same positions twice
int[] x_axis = { -2, -1, 1, 2 };
int[] y_axis = { 1, 2, 2, 1 };
// Total ways to place two Knights
long total = m * n;
total = total * (total - 1);
// Count attacking positions of a single
// Knight
long ret = 0;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
for (int k = 0; k < 4; ++k) {
int x = i + x_axis[k], y
= j + y_axis[k];
if (x >= 0 && x < m && y >= 0 && y < n)
// Since (i, j) and (x, y) are
// attacking positions for each
// other, we cannot place either of
// the two at any of these
ret += 2;
}
}
}
return (int)(total - ret);
}
// Driver code
public static void Main()
{
int n = 2, m = 3;
Console.WriteLine(numOfWays(n, m));
}
}
function numOfWays(n, m) {
// A Knight can move in 8 directions, but
// we only take downward directions to avoid
// counting same positions twice
let x_axis = [-2, -1, 1, 2];
let y_axis = [1, 2, 2, 1];
// Total ways to place two Knights
let total = m * n;
total = total * (total - 1);
// Count attacking positions of a single
// Knight
let ret = 0;
for (let i = 0; i < m; ++i) {
for (let j = 0; j < n; ++j) {
for (let k = 0; k < 4; ++k) {
let x = i + x_axis[k], y = j + y_axis[k];
if (x >= 0 && x < m && y >= 0 && y < n)
// Since (i, j) and (x, y) are attacking
// positions for each other, we cannot
// place either of the two at any of these
ret += 2;
}
}
}
return total - ret;
}
// Driver code
let n = 2, m = 3;
console.log(numOfWays(n, m));
Output
26
[Optimal Approach] Using Mathematical Formula – O(1) Time and O(1) Space
The arrangements attacks where knight to move 2 steps in the horizontal direction and 1 step in the vertical. to 4 * (n - 2) * (m - 1) and similarly for 2 steps in the vertical direction and 1 step in the horizontal. Thus the answer will be Total possible arrangement - 4 * (n - 2) * (m - 1) - 4 * (n - 1) * (m - 2) which is (n*m)*(n*m - 1) - 4 * (n - 2) * (m - 1) - 4 * (n - 1) * (m - 2)
How does this work?
- Consider knight to move 2 steps in the horizontal direction and 1 step in the vertical. So if we are at (i, j) after such moves we can reach at (i+2, j+1), (i+2, j-1), (i-2, j+1), (i-2, j-1). To have (i+2) inside the board we can have our positions 0 to n-3 i.e we have to leave the last two rows otherwise (i+2) will be out of the board. similarly for (i-2) range is possible if 2 to n-1.
- Similarly for (j+1) range will be 0 to m-2, and for (j-1) range will be 1 to m-1 i.e one column less in each case.
- So, arrangements in this case where attack possible equal to 4 * (n - 2) * (m - 1)
- Similarly, if we consider two steps in vertical and one step in horizontal we will have one less row and two less col so that two knights can attack each other. We subtract this arrangement from total arrangements which is m * n * (n * n - 1). Hence the answer will be m * n * (m * n - 1) - 4 * (n - 2) * (m - 1) - 4 * (n - 1) * (m - 2)
#include <iostream>
using namespace std;
// Function returns the count
// of arrangements
int numOfWays(int n, int m)
{
// Total arrangements
int ans = (n * m - 1) * n * m;
if (n >= 1 && m >= 2) {
// Attacks possible in one horizontal
// and two vertical steps
ans -= (4 * (n - 1) * (m - 2));
}
if (n >= 2 && m >= 1) {
// Attacks possible in Two horizontal
// and one vertical steps
ans -= (4 * (n - 2) * (m - 1));
}
return ans;
}
// Driver code
int main()
{
int n = 2, m = 3;
cout << numOfWays(n, m) << endl;
return 0;
}
import java.util.*;
class GFG {
// Function returns the count
// of arrangements
static int numOfWays(int n, int m)
{
// Total arrangements
int ans = (n * m - 1) * n * m;
if (n >= 1 && m >= 2) {
// Attacks possible in one horizontal
// and two vertical steps
ans -= (4 * (n - 1) * (m - 2));
}
if (n >= 2 && m >= 1) {
// Attacks possible in Two horizontal
// and one vertical steps
ans -= (4 * (n - 2) * (m - 1));
}
return ans;
}
// Driver code
public static void main(String[] args)
{
int n = 2, m = 3;
System.out.println(numOfWays(n, m));
}
}
# Function returns the count
# of arrangements
def numOfWays(n, m):
# Total arrangements
ans = (n * m - 1) * n * m
if n >= 1 and m >= 2:
# Attacks possible in one horizontal
# and two vertical steps
ans -= (4 * (n - 1) * (m - 2))
if n >= 2 and m >= 1:
# Attacks possible in Two horizontal
# and one vertical steps
ans -= (4 * (n - 2) * (m - 1))
return ans
# Driver code
n, m = 2, 3
print(numOfWays(n, m))
using System;
class GFG {
// Function returns the count
// of arrangements
static int numOfWays(int n, int m)
{
int ans = (n * m - 1) * n * m;
if (n >= 1 && m >= 2) {
ans -= (4 * (n - 1) * (m - 2));
}
if (n >= 2 && m >= 1) {
ans -= (4 * (n - 2) * (m - 1));
}
return ans;
}
// Driver code
public static void Main()
{
int n = 2, m = 3;
Console.WriteLine(numOfWays(n, m));
}
}
// Function returns the count
// of arrangements
function numOfWays(n, m)
{
// Total arrangements
let ans = (n * m - 1) * n * m;
if (n >= 1 && m >= 2) {
// Attacks possible in one horizontal
// and two vertical steps
ans -= (4 * (n - 1) * (m - 2));
}
if (n >= 2 && m >= 1) {
// Attacks possible in Two horizontal
// and one vertical steps
ans -= (4 * (n - 2) * (m - 1));
}
return ans;
}
// Driver code
let n = 2, m = 3;
console.log(numOfWays(n, m));
Output
26