nihonium
/
mipt_clang
Archived
1
0
Fork 0
You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

163 lines
5.2 KiB
C

2 years ago
/* Задача о ферзях */
#include <stdio.h>
#include <stdlib.h>
#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;
}