Check a Knight Tour
Autumn Tournament (2012)
Submission name: board.cpp
Problem summary
A 4×5 board contains every number from 1 to 20 exactly once. Starting at number 1, follow consecutive numbers while each next square is reachable by one chess-knight move. Print the last number reached before the first invalid move, or 20 for a complete tour.
Input
Four rows of five integers, a permutation of 1 through 20.
Output
The last consecutively reached number.
Constraints
The board has exactly 4 rows and 5 columns; each integer 1–20 occurs once.
Worked example
Original statement sample, with whitespace restored where PDF extraction merges adjacent numbers.
Input
1 20 7 14 3 6 13 2 19 10 17 8 11 4 15 12 5 16 9 18
Output
17
Solution analysis
- While reading the board, store the row and column of each number. This inverse representation lets us find consecutive labels without searching the board repeatedly.
- For labels value and value+1, calculate the absolute differences of their rows and columns. A knight move is legal exactly when those differences are (1,2) or (2,1). Stop immediately at the first illegal transition.
- In the first sample, every transition from 1 to 17 is a legal knight move. The positions of 17 and 18 differ by one row and four columns, so that transition fails and the answer is 17. There is no need to inspect later transitions.
Why it works
After processing a legal transition, every move in the consecutive prefix has been verified. The first illegal transition cannot be crossed, so the current label is precisely the last reachable one. If none fails, all 20 labels form a valid tour.
Watch out. A knight cannot move diagonally by (1,1). Check both orientations of (1,2). Return the label before the failed move, not the next label. The task validates a submitted ordering; it does not ask you to search for a tour.
Commented C++17 solution
An independently written complete program with standard headers.
// Key idea: After processing a legal transition, every move in the consecutive prefix has been
// verified. The first illegal transition cannot be crossed, so the current label is precisely the last
// reachable one.
#include<iostream>
#include<array>
#include<cstdlib>
using namespace std;
int main(){
array<int,21>row{};
array<int,21>column{};
for(int r=0;r<4;++r){
for(int c=0;c<5;++c){
int value;
cin>>value;
row[value]=r;
column[value]=c;
}
}
int reached=1;
while(reached<20){
int rowDifference=abs(row[reached+1]-row[reached]);
int columnDifference=abs(column[reached+1]-column[reached]);
bool knightMove=
(rowDifference==1&&columnDifference==2)||(rowDifference==2&&columnDifference==1);
if(!knightMove){
break;
}
++reached;
}
cout<<reached<<'\n';
}