/* Задача о ферзях */ #include #include #define _DEBUG /* Глобальная переменная для количества решений, удобнее, чем таскать указатель на счетчик по рекурсии */ int SOLUTIONS = 0; int **create_array(int N); void delete_array(int **array, int N); void print_array(int **array, int N); void solve(int **array, int *lines, int N); int **copy_array_2d(int **array, int N); int *copy_array_1d(int *array, int N); int first_empty_line(int *arrray, int N); int array_is_any_empty(int *array, int N); int count_busy_lines(int *array, int N); void put_the_queen(int **chessboard, int *lines, int N, int column, int line); int main() { int N; /* Во время отладки явно задаем размер */ #ifdef _DEBUG N = 4; #else scanf("%d", &N); #endif int **chessboard = NULL; /* * lines содержит информацию о расстановке ферзей по строкам (занято-не занято) * lines[0] - 1 строка и т.д. */ int *lines = NULL; chessboard = create_array(N); lines = (int*)calloc(N, sizeof(int)); solve(chessboard, lines, N); printf("%d", SOLUTIONS); delete_array(chessboard, N); free(lines); } /* * 0 - пустая клетка; * 1 - клетка, которую бьёт ферзь; * 2 - клетка, в которой стоит ферзь; * Если данный столбец (строка находится из lines) не занят, ставим туда ферзя и красим фрагменты доски, которые бьет новый ферзь в 1 * Если столбец занят, то пропускаем */ void solve(int **chessboard, int *lines, int N) { /* Если больше нет пустых строк(без ферзей), мы заполнили доску ферзями */ if (!array_is_any_empty(lines, N)) { print_array(chessboard, N); SOLUTIONS++; } else { /* Создаем копию текущего состояния */ int **chessboard1 = copy_array_2d(chessboard, N); int *lines1 = copy_array_1d(lines, N); /* Ищем первую строку без ферзя на ней */ int line = first_empty_line(lines1, N); /* Будем пробовать ставить ферзя на разные места в строке */ for (int column = 0; column < N; column++) { put_the_queen(chessboard1, lines1, N, column, line); /* Если смогли поставить ферзя (т.е. кол-во пустых строк стало не равно предыдущему значению), то рекурсивно рассматриваем дальше */ if (!(count_busy_lines(lines1, N) == count_busy_lines(lines, N))) { solve(chessboard1, lines1, N); delete_array(chessboard1, N); /* Возвращем массив в состояние до входа в рекурсию, соответствующего ферзя убираем */ chessboard1 = copy_array_2d(chessboard, N); lines1[line] = 0; } } free(lines1); delete_array(chessboard1, N); } } void put_the_queen(int **chessboard, int *lines, int N, int column, int line) { /* Если клетка занята/под боем - пропускаем */ if (chessboard[line][column]) { return; } /* "Занимаем" строку ферзем */ lines[line] = 1; /* Проверяем, в какие клетки доски попадет ферзь и красим их в 1 */ for (int x = 0; x < N; x++) { for (int y = 0; y < N; y++) { if (abs(x - column) == abs(y - line) || x == column || y == line) { chessboard[y][x] = 1; } } } /* Ставим ферзя */ chessboard[line][column] = 2; } 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 print_array(int **array, int N) { printf("............\n"); for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { printf("%c ", (array[i][j] == 2) ? ('Q') : ('*')); } printf("\n"); } printf("............\n"); } int **copy_array_2d(int **array, int N) { int **array1 = create_array(N); for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { array1[i][j] = array[i][j]; } } return array1; } int *copy_array_1d(int *array, int N) { int *array1 = (int*)calloc(N, sizeof(int)); for (int i = 0; i < N; i++) { array1[i] = array[i]; } return array1; } int first_empty_line(int *array, int N) { for (int i = 0; i < N; i++) { if (array[i] == 0) { return i; } } return -1; } int array_is_any_empty(int *array, int N) { for (int i = 0; i < N; i++) { if (array[i] == 0) { return 1; } } return 0; } int count_busy_lines(int *array, int N) { int sum = 0; for (int i = 0; i < N; i++) { if (array[i] == 1) { sum++; } } return sum; }