/* Задача о ходе коня - правило Варнсдорфа */ #include #include #include /* Возможные смещения для хода коня */ const int moves[8][2] = { {-2, -1}, {-2, 1}, /* 2 вниз, влево-вправо */ {2, -1}, {2, 1}, /* 2 вверх, влево-вправо */ {-1, -2}, {1, -2}, /* 2 влево, вверх-вниз */ {-1, 2}, {1, 2} /* 2 вправо, вверх-вниз */ }; int **create_array(int N); void delete_array(int **array, int N); void reset_array(int **array, int N); /* Количество ходов из заданной клетки */ int sum_of_moves(int **array, int N, int x1, int y1); /* x1 - строка, y1 - столбец */ void solve(int **array, int N, int x1, int y1, int *move_n); void print_array(int **array, int N); /* Проверка суммой */ int sum_check(int **array, int N); int check(int **array, int N, int x, int y); int is_looped(int **array, int N); int main() { /* Размер доски, доску считаем квадратной */ size_t N; scanf("%zu", &N); /* Массив, представляющий доску */ int **chessboard = NULL; int move_n = 1; int x1 = 1, y1 = 1; chessboard = create_array(N); /* Ставим коня */ chessboard[x1][y1] = 1; solve(chessboard, N, x1, y1, &move_n); int number_solution = check(chessboard, N, x1, y1); if (number_solution) print_array(chessboard, N); else printf("Нет решения.\n"); delete_array(chessboard, N); } void solve(int **array, int N, int x1, int y1, int *move_n) { int min = INT_MAX; /* Клетки для итераций */ int x2 = 0, y2 = 0; /* Выбранная клетка */ int x3 = 0, y3 = 0; /* Количество ходов из очередной клетки */ int sum = 0; /* 0 - все соседние клетки заняты, либо тупик, либо конечный результат; * 1 - продолжаем рекурсию со следующей клетки */ int cont = 0; /* Перебираем возможные ходы */ for (int i = 0; i < 8; i++) { x2 = x1 + moves[i][0]; y2 = y1 + moves[i][1]; /* Не ушли ли за доску */ if ((x2 >= 0 && y2 >= 0) && (x2 < N && y2 < N)) { /* Не были ли уже в этой клетке */ if (array[x2][y2] == 0) { /* По правилу Варнсдорфа выбираем поле, с котрого можно пойти на минимальное количество других */ sum = sum_of_moves(array, N, x2, y2); if (sum < min) { cont = 1; min = sum; x3 = x2; y3 = y2; } } } } if (cont) { *move_n += 1; array[x3][y3] = *move_n; solve(array, N, x3, y3, move_n); } /* Когда не находится, куда еще идти, "выпадаем" из рекурсии. Либо мы нашли решение, либо попали в тупик (маловероятно, но возможно) */ } int sum_of_moves(int **array, int N, int x1, int y1) { int sum = 0; int x2 = 0, y2 = 0; /* Перебираем возможные ходы */ for (int i = 0; i < 8; i++) { x2 = x1 + moves[i][0]; y2 = y1 + moves[i][1]; /* Не вылезли ли за доску */ if ((x2 >= 0 && y2 >= 0) && (x2 < N && y2 < N)) { if (array[x2][y2] == 0) { sum += 1; } } } return sum; } /* Сумма элементов массива должна быть равна сумме чисел от 1 до N (т.е. обошли всю доску) */ int sum_check(int **array, int N) { long long unsigned sum = 0; long long unsigned total_sum = 0; if (N % 2 == 1) sum = (1 + N * N) / 2 * ( N * N); else sum = (N * N) / 2 * (N * N + 1); for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) total_sum += array[i][j]; if (sum == total_sum) { return 1; } return 0; } int check(int **array, int N, int x, int y) { /* Решение верно */ if (sum_check(array, N)) { return 1; } /* Если мы попали в тупик, то пробуем найти иной путь */ else { int move_n = 1; /* Начинаем перебирать все решения */ for (int x1 = 0; x1 < N; x1++) { for (int y1 = 0; y1 < N; y1++) { /* Ставим коня на пустую доску */ move_n = 1; reset_array(array, N); array[x1][y1] = 1; solve(array, N, x1, y1, &move_n); /* Если другое решение подходит, то выдаем его */ if (sum_check(array, N) && is_looped(array, N)) { int difference = array[x][y] - 1; /* Изменяем ходы, будто мы ходили с другого поля */ for (int x2 = 0; x2 < N; x2++) { for (int y2 = 0; y2 < N; y2++) { if (array[x2][y2] > difference) { array[x2][y2] -= difference; } else { array[x2][y2] = N * N + array[x2][y2] - difference; } } } return 2; } } } return 0; } } /* Проверяем замкнутость маршрута */ int is_looped(int **array, int N) { int start_x = 0, start_y = 0; int end_x = 0, end_y = 0; /* Ищем */ for (int x = 0; x < N; x++ ) for (int y = 0; y < N; y++) { if (array[x][y] == 1) { start_x = x; start_y = y; } else if (array[x][y] == N*N) { end_x = x; end_y = y; } } /* Если можем пойти конем из одной в другую, то маршрут замкнут */ if ((abs(end_x - start_x) == 1 && abs(end_y - start_y) == 2) || (abs(end_x - start_x) == 2 && abs(end_y - start_y) == 1)) return 1; else return 0; } int **create_array(int N) { int **array = (int**)calloc(N, sizeof(int*)); for (int i = 0; i < N; i++) array[i] = (int*)calloc(N, sizeof(int)); return array; } void delete_array(int **array, int N) { for (int i = 0; i < N; i++) free(array[i]); free(array); } void reset_array(int **array, int N) { for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) array[i][j] = 0; } void print_array(int **array, int N) { for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) printf("%3d ", array[i][j]); printf("\n"); } }