Pers.narod.ru. Алгоритмы. Путь коня по шахматной доске |
Ещё одна классическая задача. Нужно обойти конём все поля шахматной доски, начав с некоторого выбранного поля. Приведённая программа - консольная, но она иллюстрирует свои действия печатью того, какие варианты сейчас перебираются (на это и уходит 99% времени работы, лень было писать прямо в видеопамять). Константа N в программе задаёт размер доски, сейчас там значение 5 - при значении N=8, думаю, будет считаться довольно долго (метод простейший - полный рекурсивный перебор возможных путей). Нумерация полей - слева и сверху, с нуля. Путь из левого верхнего угла для доски 5x5 будет успешно найден.
//Путь коня по шахматной доске
#include <stdio.h>
#include <conio.h>
const int N=5; // размер доски
int desk[N][N]; // поля доски
int nstep; // номер шага
void Print (void) {
int i,j;
clrscr();
for (i=0; i<N; i++)
for (j=0; j<N; j++) {
gotoxy (j*3+1 ,i+1);
printf ("%02d ", desk[i][j]);
}
}
int step(int x0, int y0) {
static int xy[8][2] = {{ 1,-2},{ 1, 2},{-1,-2},{-1, 2},
{ 2,-1},{ 2, 1},{-2, 1},{-2,-1} // ходы коня - возможные
};
int i; // локальный параметр - номер хода
Print();
if (x0 < 0 || x0 >N-1 || y0 < 0 || y0 >N-1 ) return(0); // выход за пределы доски
if (desk[x0][y0] !=0)
return(0); // поле уже пройдено
desk[x0][y0] = ++nstep; // отметить свободное поле
if (nstep == N*N)
return(1); // все поля отмечены - успех
for (i=0; i<8; i++)
if (step(x0+xy[i][0], y0+xy[i][1]))
return(1); // поиск успешного хода
nstep--; // вернуться на ход назад
desk[x0][y0] = 0; // стереть отметку поля
return(0); // последовательность не найдена
}
int Path(int x0, int y0)
{
int i,j; // очистка доски
for (i=0; i<N; i++)
for (j=0; j<N; j++) desk[i][j] =0;
nstep = 0; // установить номер шага
return step(x0,y0); // вызвать функцию для исходной
} // позиции
void main (void) {
int n=Path (0,0); // нумерация полей - слева и сверху, с нуля
Print();
printf ("\nRes=%d",n);
}
P.S. Кстати, не так уж долго это работает, вот листинги некоторых результатов с вычислением требуемого числа шагов.
На доске 4*4 или менее решения не существует. Для доски 5*5: 01 08 19 14 25 18 13 02 09 06 03 20 07 24 15 12 17 22 05 10 21 04 11 16 23 Res=1,Steps=614838 Для доски 6*6: 01 24 27 12 09 36 22 11 02 25 28 13 03 26 23 10 35 08 18 21 04 31 14 29 05 32 19 16 07 34 20 17 06 33 30 15 Res=1,Steps=82995890 Для доски 7*7: 01 20 29 42 45 38 31 28 43 02 19 30 41 46 03 18 21 44 39 32 37 22 27 04 17 36 47 40 05 08 11 26 33 16 35 12 23 06 09 14 25 48 07 10 13 24 49 34 15 Res=1,Steps=84376540 Для доски 8*8: 36 31 48 57 38 41 50 59 47 56 37 30 49 58 39 42 32 35 54 45 40 29 60 51 55 46 33 26 53 62 43 28 34 25 06 13 44 27 52 61 07 14 17 24 05 12 63 20 16 23 02 09 18 21 04 11 01 08 15 22 03 10 19 64 Res=1,Steps=174326079 Для доски 9*9:
В этих тестах использовалась чуть изменённая версия программы (убрана промежуточная печать и добавлен общий счётчик числа шагов).
Кроме того, массив xy незачем делать локальным. Для доски 8x8 с начального поля (0,0) решение
в разумное время вообще не нашлось, а вот с левого нижнего поля доски
int n=Path (N-1,0);
получилось быстро.
#include <stdio.h>
#include <conio.h>
const int N=7;
int desk[N][N];
int nstep;
double p=0; //Число шагов
static int xy[8][2] = {
{ 1,-2},{ 1, 2},{-1,-2},{-1, 2},{ 2,-1},{ 2, 1},{-2, 1},{-2,-1}
};
int step(int x0, int y0) {
int i;
p++;
if (x0 < 0 || x0 >N-1 || y0 < 0 || y0 >N-1 ) return(0);
if (desk[x0][y0] !=0) return(0);
desk[x0][y0] = ++nstep;
if (nstep == N*N) return(1);
for (i=0; i<8; i++)
if (step(x0+xy[i][0], y0+xy[i][1])) return(1);
nstep--;
desk[x0][y0] = 0;
return(0);
}
int Path(int x0, int y0) {
int i,j;
for (i=0; i<N; i++)
for (j=0; j<N; j++) desk[i][j] =0;
nstep = 0;
return step(x0,y0);
}
void main (void) {
int n=Path (0,0);
clrscr();
int i,j;
for (i=0; i<N; i++)
for (j=0; j<N; j++) {
gotoxy (j*3+1 ,i+1);
printf ("%02d ", desk[i][j]);
}
printf ("\nRes=%d,Steps=%.0lf",n,p);
}
Следует понимать, что как и любое рекурсивное решение, программа активно пользуется стеком и при "плохой" компиляции может привести к переполнению стека.
|
|