Archived
1
0
Fork 0
This repository has been archived on 2022-06-20. You can view files and clone it, but cannot push or open issues or pull requests.
mipt_clang/algo/second/queens.c
2022-06-18 20:10:34 +03:00

162 lines
5.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Задача о ферзях */
#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;
}