diff --git a/algo/second/queens.c b/algo/second/queens.c new file mode 100644 index 0000000..c151d08 --- /dev/null +++ b/algo/second/queens.c @@ -0,0 +1,162 @@ +/* Задача о ферзях */ +#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; +}