queens
This commit is contained in:
parent
88481278ea
commit
33ddebed69
1 changed files with 162 additions and 0 deletions
162
algo/second/queens.c
Normal file
162
algo/second/queens.c
Normal file
|
@ -0,0 +1,162 @@
|
|||
/* Задача о ферзях */
|
||||
#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;
|
||||
}
|
Reference in a new issue