N-Queens — Practice Tasks¶
All tasks must be solved in Go, Java, and Python. Each task ships with a precise spec and starter code in all three languages. Implement the backtracking / bitmask logic and validate against the evaluation criteria. Always validate small
Nagainst the known sequence 1, 0, 0, 2, 10, 4, 40, 92, 352 before trusting larger runs.
Beginner Tasks (5)¶
Task 1 — O(1) safety check¶
Problem. Implement safe(r, c, cols, diag, anti, n) returning whether a queen at (r, c) is non-attacking given the three occupancy arrays. Use the diagonal index r - c + n - 1 and anti-diagonal index r + c.
Input / Output spec. - Inputs: r, c, the three boolean arrays, and n. - Output: true if the square is free of column/diagonal/anti-diagonal attacks, else false.
Constraints. 1 ≤ n ≤ 20, 0 ≤ r, c < n. diag and anti have length 2n - 1.
Hint. Three array reads, ANDed together. Remember to shift the diagonal index by + (n - 1).
Starter — Go.
package main
import "fmt"
func safe(r, c int, cols, diag, anti []bool, n int) bool {
// TODO: return true iff column c, diag r-c+n-1, and anti r+c are all free
return false
}
func main() {
n := 4
cols := make([]bool, n)
diag := make([]bool, 2*n-1)
anti := make([]bool, 2*n-1)
cols[0] = true
diag[0-0+n-1] = true
anti[0+0] = true
fmt.Println(safe(1, 2, cols, diag, anti, n)) // true
fmt.Println(safe(1, 1, cols, diag, anti, n)) // false (same diag as (0,0))
}
Starter — Java.
public class Task1 {
static boolean safe(int r, int c, boolean[] cols, boolean[] diag, boolean[] anti, int n) {
// TODO
return false;
}
public static void main(String[] args) {
int n = 4;
boolean[] cols = new boolean[n], diag = new boolean[2*n-1], anti = new boolean[2*n-1];
cols[0] = true; diag[n-1] = true; anti[0] = true;
System.out.println(safe(1, 2, cols, diag, anti, n)); // true
System.out.println(safe(1, 1, cols, diag, anti, n)); // false
}
}
Starter — Python.
def safe(r, c, cols, diag, anti, n):
# TODO: return True iff column, diagonal, anti-diagonal are all free
return False
if __name__ == "__main__":
n = 4
cols = [False] * n
diag = [False] * (2 * n - 1)
anti = [False] * (2 * n - 1)
cols[0] = True; diag[n - 1] = True; anti[0] = True
print(safe(1, 2, cols, diag, anti, n)) # True
print(safe(1, 1, cols, diag, anti, n)) # False
Evaluation. Returns correct safety for all combinations; uses the shifted diagonal index.
Task 2 — Count solutions for a single N¶
Problem. Given N, return the number of valid arrangements using the boolean-array backtracking.
Input / Output spec. Read N; print the count.
Constraints. 1 ≤ N ≤ 12.
Hint. Recurse on the row; count++ at r == N; pair every mark with an undo.
Starter — Go.
package main
import "fmt"
func count(n int) int {
// TODO: boolean-array backtracking
return 0
}
func main() {
var n int
fmt.Scan(&n)
fmt.Println(count(n))
}
Starter — Java.
import java.util.*;
public class Task2 {
static int count(int n) {
// TODO
return 0;
}
public static void main(String[] args) {
int n = new Scanner(System.in).nextInt();
System.out.println(count(n));
}
}
Starter — Python.
def count(n):
# TODO: boolean-array backtracking
return 0
if __name__ == "__main__":
print(count(int(input())))
Evaluation. count(8) == 92, count(6) == 4, count(2) == 0.
Task 3 — Find and print one solution¶
Problem. Print one valid board (Q/.), or NONE if no solution exists.
Input / Output spec. Read N; print N lines, or NONE.
Constraints. 1 ≤ N ≤ 30.
Hint. Early-exit backtracking: return true at the base case and propagate up.
Starter — Go.
package main
import "fmt"
func main() {
var n int
fmt.Scan(&n)
// TODO: find one solution, print board or "NONE"
_ = n
}
Starter — Java.
import java.util.*;
public class Task3 {
public static void main(String[] args) {
int n = new Scanner(System.in).nextInt();
// TODO: find one solution, print board or "NONE"
}
}
Starter — Python.
def main():
n = int(input())
# TODO: find one solution, print board or "NONE"
if __name__ == "__main__":
main()
Evaluation. Prints a board whose columns, r-c, and r+c are all distinct; prints NONE for N = 2, 3.
Task 4 — Validate a candidate board¶
Problem. Given a permutation pos[] (pos[r] = column in row r), return whether it is a valid N-Queens solution.
Input / Output spec. Read N, then N integers pos[0..N-1]. Print VALID or INVALID.
Constraints. 1 ≤ N ≤ 1000, 0 ≤ pos[r] < N.
Hint. Use three sets; insert pos[r], r - pos[r], r + pos[r] and detect any repeat.
Starter — Go.
package main
import "fmt"
func valid(pos []int) bool {
// TODO: check columns, r-c, r+c all distinct
return false
}
func main() {
var n int
fmt.Scan(&n)
pos := make([]int, n)
for i := range pos {
fmt.Scan(&pos[i])
}
if valid(pos) {
fmt.Println("VALID")
} else {
fmt.Println("INVALID")
}
}
Starter — Java.
import java.util.*;
public class Task4 {
static boolean valid(int[] pos) {
// TODO
return false;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] pos = new int[n];
for (int i = 0; i < n; i++) pos[i] = sc.nextInt();
System.out.println(valid(pos) ? "VALID" : "INVALID");
}
}
Starter — Python.
def valid(pos):
# TODO: check columns, r-c, r+c all distinct
return False
if __name__ == "__main__":
n = int(input())
pos = [int(x) for x in input().split()]
print("VALID" if valid(pos) else "INVALID")
Evaluation. Runs in O(N); correctly rejects column and both diagonal conflicts.
Task 5 — Solution-count table¶
Problem. Print N and its solution count for N = 1..K.
Input / Output spec. Read K; print K lines N count.
Constraints. 1 ≤ K ≤ 12.
Hint. Reuse your counter from Task 2 in a loop.
Starter — Go.
package main
import "fmt"
func count(n int) int { return 0 /* TODO */ }
func main() {
var k int
fmt.Scan(&k)
for n := 1; n <= k; n++ {
fmt.Println(n, count(n))
}
}
Starter — Java.
import java.util.*;
public class Task5 {
static int count(int n) { return 0; /* TODO */ }
public static void main(String[] args) {
int k = new Scanner(System.in).nextInt();
for (int n = 1; n <= k; n++) System.out.println(n + " " + count(n));
}
}
Starter — Python.
def count(n):
return 0 # TODO
if __name__ == "__main__":
k = int(input())
for n in range(1, k + 1):
print(n, count(n))
Evaluation. Matches 1,0,0,2,10,4,40,92,352,724,2680,14200.
Intermediate Tasks (4)¶
Task 6 — Bitmask counter¶
Problem. Count solutions using the three-integer bitmask recursion (lowbit iteration, diagonal shifting, masks by value).
Input / Output spec. Read N; print the count.
Constraints. 1 ≤ N ≤ 16.
Hint. avail = ~(cols|diag|anti) & full; p = avail & -avail; recurse with (diag|p)<<1 & full, (anti|p)>>1.
Starter — Go.
package main
import "fmt"
func count(n int) int {
full := (1 << n) - 1
// TODO: bitmask recursion
_ = full
return 0
}
func main() {
var n int
fmt.Scan(&n)
fmt.Println(count(n))
}
Starter — Java.
import java.util.*;
public class Task6 {
static int full;
static int rec(int cols, int diag, int anti) {
// TODO
return 0;
}
static int count(int n) { full = (1 << n) - 1; return rec(0, 0, 0); }
public static void main(String[] args) {
System.out.println(count(new Scanner(System.in).nextInt()));
}
}
Starter — Python.
def count(n):
full = (1 << n) - 1
# TODO: bitmask recursion
return 0
if __name__ == "__main__":
print(count(int(input())))
Evaluation. Matches the boolean version for N = 1..14; noticeably faster.
Task 7 — Count with symmetry reduction¶
Problem. Count solutions but only search the left half of row-0 columns, double the result, and handle the odd-N center column once.
Input / Output spec. Read N; print the count.
Constraints. 1 ≤ N ≤ 16.
Hint. Loop c in 0..N/2-1 (double each), then if N odd add the center column N/2 once.
Starter — Go.
package main
import "fmt"
func count(n int) int {
// TODO: bitmask + left-half symmetry, double, center once
return 0
}
func main() {
var n int
fmt.Scan(&n)
fmt.Println(count(n))
}
Starter — Java.
import java.util.*;
public class Task7 {
static int count(int n) {
// TODO
return 0;
}
public static void main(String[] args) {
System.out.println(count(new Scanner(System.in).nextInt()));
}
}
Starter — Python.
def count(n):
# TODO: bitmask + left-half symmetry
return 0
if __name__ == "__main__":
print(count(int(input())))
Evaluation. Equals the non-symmetry count for all N; about 2× faster. Verify odd N (e.g. 5, 7, 9) carefully.
Task 8 — Print all distinct solutions¶
Problem. Print every solution board, separated by blank lines, with a header Solution k:.
Input / Output spec. Read N; print all boards and finally Total: <count>.
Constraints. 1 ≤ N ≤ 8.
Hint. Count-all backtracking; reconstruct the board from pos[] at each leaf.
Starter — Go.
package main
import "fmt"
func main() {
var n int
fmt.Scan(&n)
// TODO: print all boards, then "Total: <count>"
_ = n
}
Starter — Java.
import java.util.*;
public class Task8 {
public static void main(String[] args) {
int n = new Scanner(System.in).nextInt();
// TODO: print all boards, then "Total: <count>"
}
}
Starter — Python.
def main():
n = int(input())
# TODO: print all boards, then "Total: <count>"
if __name__ == "__main__":
main()
Evaluation. For N = 5 prints 10 boards; the trailing total matches the known count.
Task 9 — Last-row popcount optimization¶
Problem. Implement the bitmask counter but collapse the final row using popcount(available).
Input / Output spec. Read N; print the count.
Constraints. 1 ≤ N ≤ 16.
Hint. When row == N-1, return the number of set bits in available instead of recursing.
Starter — Go.
package main
import (
"fmt"
"math/bits"
)
func count(n int) int {
full := (1 << n) - 1
_ = full
_ = bits.OnesCount
// TODO: recursion with last-row popcount
return 0
}
func main() {
var n int
fmt.Scan(&n)
fmt.Println(count(n))
}
Starter — Java.
import java.util.*;
public class Task9 {
static int n, full;
static int rec(int row, int cols, int diag, int anti) {
// TODO: when row == n-1 return Integer.bitCount(available)
return 0;
}
static int count(int N) { n = N; full = (1 << N) - 1; return N == 0 ? 1 : rec(0,0,0,0); }
public static void main(String[] args) {
System.out.println(count(new Scanner(System.in).nextInt()));
}
}
Starter — Python.
def count(n):
full = (1 << n) - 1
# TODO: recursion with last-row popcount via bin(x).count("1")
return 0
if __name__ == "__main__":
print(count(int(input())))
Evaluation. Matches the plain bitmask count; measurably faster on N = 14..16.
Advanced Tasks (3)¶
Task 10 — Constructive single solution for huge N¶
Problem. Output one valid board for large N in O(N) using the constructive formula (no search). Print pos[] as N space-separated columns, or NONE for N = 2, 3.
Input / Output spec. Read N; print pos[0..N-1] or NONE.
Constraints. 1 ≤ N ≤ 1,000,000.
Hint. Handle N mod 6; interleave even and odd columns with the small fixups for residues 2 and 3. Then verify with the O(N) triple-set check.
Starter — Go.
package main
import "fmt"
func construct(n int) []int {
// TODO: O(N) constructive placement; return nil for n==2 or 3
return nil
}
func main() {
var n int
fmt.Scan(&n)
pos := construct(n)
if pos == nil {
fmt.Println("NONE")
return
}
for i, c := range pos {
if i > 0 {
fmt.Print(" ")
}
fmt.Print(c)
}
fmt.Println()
}
Starter — Java.
import java.util.*;
public class Task10 {
static int[] construct(int n) {
// TODO: O(N) construction; return null for n == 2 or 3
return null;
}
public static void main(String[] args) {
int n = new Scanner(System.in).nextInt();
int[] pos = construct(n);
if (pos == null) { System.out.println("NONE"); return; }
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) { if (i > 0) sb.append(' '); sb.append(pos[i]); }
System.out.println(sb);
}
}
Starter — Python.
def construct(n):
# TODO: O(N) constructive placement; return None for n == 2 or 3
return None
if __name__ == "__main__":
n = int(input())
pos = construct(n)
print("NONE" if pos is None else " ".join(map(str, pos)))
Evaluation. For N = 1,000,000 runs in well under a second; the output passes an independent O(N) validity check.
Task 11 — N-Queens completion¶
Problem. Given pre-placed queens, count the number of completions (full solutions extending them). Validate the pre-placed queens are mutually non-attacking first; if not, output 0.
Input / Output spec. Read N, then M, then M lines r c of fixed queens. Print the number of completions.
Constraints. 1 ≤ N ≤ 15, 0 ≤ M ≤ N, at most one fixed queen per row.
Hint. Seed cols/diag/anti with the fixed queens; at a fixed row, descend with that queen's column only (no loop). Add a node budget for safety (completion is NP-complete).
Starter — Go.
package main
import "fmt"
func completions(n int, fixed []int) int {
// fixed[r] = column or -1
// TODO: seed masks, search remaining rows; return 0 on a pre-placed clash
return 0
}
func main() {
var n, m int
fmt.Scan(&n, &m)
fixed := make([]int, n)
for i := range fixed {
fixed[i] = -1
}
for i := 0; i < m; i++ {
var r, c int
fmt.Scan(&r, &c)
fixed[r] = c
}
fmt.Println(completions(n, fixed))
}
Starter — Java.
import java.util.*;
public class Task11 {
static int completions(int n, int[] fixed) {
// TODO
return 0;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), m = sc.nextInt();
int[] fixed = new int[n];
Arrays.fill(fixed, -1);
for (int i = 0; i < m; i++) { int r = sc.nextInt(), c = sc.nextInt(); fixed[r] = c; }
System.out.println(completions(n, fixed));
}
}
Starter — Python.
def completions(n, fixed):
# fixed[r] = column or -1
# TODO
return 0
if __name__ == "__main__":
n, m = map(int, input().split())
fixed = [-1] * n
for _ in range(m):
r, c = map(int, input().split())
fixed[r] = c
print(completions(n, fixed))
Evaluation. With no fixed queens, equals the full count for N. A self-attacking prefix yields 0. Pinning the row-0 queen reduces the count consistently with full enumeration.
Task 12 — Parallel counting¶
Problem. Count all solutions by splitting on the row-0 column across worker threads/goroutines and summing partial counts. Result must match the single-threaded count exactly.
Input / Output spec. Read N; print the count.
Constraints. 1 ≤ N ≤ 16. Use 64-bit accumulators.
Hint. Each row-0 column defines an independent subtree (masks by value). Sum the partials under a mutex or via channels/futures.
Starter — Go.
package main
import (
"fmt"
"sync"
)
func count(n int) int64 {
full := (1 << n) - 1
var solve func(cols, diag, anti int) int64
solve = func(cols, diag, anti int) int64 {
// TODO: bitmask recursion returning int64
_ = full
return 0
}
var wg sync.WaitGroup
var mu sync.Mutex
var total int64
for c := 0; c < n; c++ {
c := c
wg.Add(1)
go func() {
defer wg.Done()
p := 1 << c
sub := solve(p, p<<1, p>>1) // TODO: pass shifted masks correctly
mu.Lock()
total += sub
mu.Unlock()
}()
}
wg.Wait()
return total
}
func main() {
var n int
fmt.Scan(&n)
fmt.Println(count(n))
}
Starter — Java.
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class Task12 {
static int full;
static long solve(int cols, int diag, int anti) {
// TODO
return 0;
}
static long count(int n) throws Exception {
full = (1 << n) - 1;
AtomicLong total = new AtomicLong();
ExecutorService pool = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors());
List<Future<?>> fs = new ArrayList<>();
for (int c = 0; c < n; c++) {
int cc = c;
fs.add(pool.submit(() -> {
int p = 1 << cc;
total.addAndGet(solve(p, (p << 1) & full, p >> 1));
}));
}
for (Future<?> f : fs) f.get();
pool.shutdown();
return total.get();
}
public static void main(String[] args) throws Exception {
System.out.println(count(new Scanner(System.in).nextInt()));
}
}
Starter — Python.
from concurrent.futures import ProcessPoolExecutor
def _subtree(args):
n, c = args
full = (1 << n) - 1
def solve(cols, diag, anti):
# TODO: bitmask recursion
return 0
p = 1 << c
return solve(p, (p << 1) & full, p >> 1)
def count(n):
with ProcessPoolExecutor() as ex:
return sum(ex.map(_subtree, [(n, c) for c in range(n)]))
if __name__ == "__main__":
print(count(int(input())))
Evaluation. Parallel total equals the single-threaded total for all N; speedup scales with cores; 64-bit accumulators avoid overflow.
Validation Checklist¶
- Counts match A000170 (
1,0,0,2,10,4,40,92,352,…) for every implementation. -
N = 2andN = 3return 0 /NONE. - Diagonal index uses
r - c + N - 1(size2N - 1). - Every
markis paired with anunmark(boolean version) or masks are by value (bitmask version). - Symmetry version never double-counts the odd-
Ncenter column. - Constructed large-
Nboards pass an independentO(N)validity check. - Parallel and single-threaded counts agree exactly; counters are 64-bit.