second algo, knight
This commit is contained in:
parent
1a63610dff
commit
88481278ea
2 changed files with 224 additions and 0 deletions
16
algo/second/Makefile
Normal file
16
algo/second/Makefile
Normal file
|
@ -0,0 +1,16 @@
|
|||
CC=gcc
|
||||
CFLAGS=-Wall -lm -Wall -Werror=sign-compare -Werror=array-bounds -Werror=maybe-uninitialized -Werror=unused-parameter -Werror=maybe-uninitialized -Werror=cast-qual
|
||||
|
||||
EXECS=knight
|
||||
|
||||
build_knight: knight.c
|
||||
$(CC) $(CFLAGS) knight.c -o knight
|
||||
knight_run: knight
|
||||
./knight
|
||||
|
||||
build_queens: queens.c
|
||||
$(CC) $(CFLAGS) queens.c -o queens
|
||||
queens_run: queens
|
||||
./queens
|
||||
clean:
|
||||
rm -f $(EXECS)
|
208
algo/second/knight.c
Normal file
208
algo/second/knight.c
Normal file
|
@ -0,0 +1,208 @@
|
|||
/* Задача о ходе коня - правило Варнсдорфа */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* Возможные смещения для хода коня */
|
||||
const int moves[8][2] = {
|
||||
{-2, -1}, {-2, 1}, /* 2 вниз, влево-вправо */
|
||||
{2, -1}, {2, 1}, /* 2 вверх, влево-вправо */
|
||||
{-1, -2}, {1, -2}, /* 2 влево, вверх-вниз */
|
||||
{-1, 2}, {1, 2} /* 2 вправо, вверх-вниз */
|
||||
};
|
||||
|
||||
int **create_array(int N);
|
||||
void delete_array(int **array, int N);
|
||||
void reset_array(int **array, int N);
|
||||
/* Количество ходов из заданной клетки */
|
||||
int sum_of_moves(int **array, int N, int x1, int y1);
|
||||
/* x1 - строка, y1 - столбец */
|
||||
void solve(int **array, int N, int x1, int y1, int *move_n);
|
||||
void print_array(int **array, int N);
|
||||
/* Проверка суммой */
|
||||
int sum_check(int **array, int N);
|
||||
int check(int **array, int N, int x, int y);
|
||||
int is_looped(int **array, int N);
|
||||
|
||||
int main() {
|
||||
/* Размер доски, доску считаем квадратной */
|
||||
size_t N;
|
||||
scanf("%zu", &N);
|
||||
/* Массив, представляющий доску */
|
||||
int **chessboard = NULL;
|
||||
int move_n = 1;
|
||||
int x1 = 1, y1 = 1;
|
||||
|
||||
chessboard = create_array(N);
|
||||
|
||||
/* Ставим коня */
|
||||
chessboard[x1][y1] = 1;
|
||||
solve(chessboard, N, x1, y1, &move_n);
|
||||
|
||||
int number_solution = check(chessboard, N, x1, y1);
|
||||
|
||||
if (number_solution)
|
||||
print_array(chessboard, N);
|
||||
else
|
||||
printf("Нет решения.\n");
|
||||
delete_array(chessboard, N);
|
||||
}
|
||||
|
||||
void solve(int **array, int N, int x1, int y1, int *move_n) {
|
||||
int min = INT_MAX;
|
||||
/* Клетки для итераций */
|
||||
int x2 = 0, y2 = 0;
|
||||
/* Выбранная клетка */
|
||||
int x3 = 0, y3 = 0;
|
||||
/* Количество ходов из очередной клетки */
|
||||
int sum = 0;
|
||||
/* 0 - все соседние клетки заняты, либо тупик, либо конечный результат;
|
||||
* 1 - продолжаем рекурсию со следующей клетки */
|
||||
int cont = 0;
|
||||
|
||||
/* Перебираем возможные ходы */
|
||||
for (int i = 0; i < 8; i++) {
|
||||
x2 = x1 + moves[i][0];
|
||||
y2 = y1 + moves[i][1];
|
||||
/* Не ушли ли за доску */
|
||||
if ((x2 >= 0 && y2 >= 0) && (x2 < N && y2 < N)) {
|
||||
/* Не были ли уже в этой клетке */
|
||||
if (array[x2][y2] == 0) {
|
||||
/* По правилу Варнсдорфа выбираем поле, с котрого можно пойти на минимальное количество других */
|
||||
sum = sum_of_moves(array, N, x2, y2);
|
||||
if (sum < min) {
|
||||
cont = 1;
|
||||
min = sum;
|
||||
x3 = x2; y3 = y2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cont) {
|
||||
*move_n += 1;
|
||||
array[x3][y3] = *move_n;
|
||||
solve(array, N, x3, y3, move_n);
|
||||
}
|
||||
/* Когда не находится, куда еще идти, "выпадаем" из рекурсии. Либо мы нашли решение, либо попали в тупик (маловероятно, но возможно) */
|
||||
}
|
||||
|
||||
int sum_of_moves(int **array, int N, int x1, int y1) {
|
||||
int sum = 0;
|
||||
int x2 = 0, y2 = 0;
|
||||
/* Перебираем возможные ходы */
|
||||
for (int i = 0; i < 8; i++) {
|
||||
x2 = x1 + moves[i][0];
|
||||
y2 = y1 + moves[i][1];
|
||||
/* Не вылезли ли за доску */
|
||||
if ((x2 >= 0 && y2 >= 0) && (x2 < N && y2 < N)) {
|
||||
if (array[x2][y2] == 0) {
|
||||
sum += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
/* Сумма элементов массива должна быть равна сумме чисел от 1 до N (т.е. обошли всю доску) */
|
||||
int sum_check(int **array, int N) {
|
||||
long long unsigned sum = 0;
|
||||
long long unsigned total_sum = 0;
|
||||
if (N % 2 == 1)
|
||||
sum = (1 + N * N) / 2 * ( N * N);
|
||||
else
|
||||
sum = (N * N) / 2 * (N * N + 1);
|
||||
for (int i = 0; i < N; i++)
|
||||
for (int j = 0; j < N; j++)
|
||||
total_sum += array[i][j];
|
||||
|
||||
if (sum == total_sum) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int check(int **array, int N, int x, int y) {
|
||||
/* Решение верно */
|
||||
if (sum_check(array, N)) {
|
||||
return 1;
|
||||
}
|
||||
/* Если мы попали в тупик, то пробуем найти иной путь */
|
||||
else {
|
||||
int move_n = 1;
|
||||
|
||||
/* Начинаем перебирать все решения */
|
||||
for (int x1 = 0; x1 < N; x1++) {
|
||||
for (int y1 = 0; y1 < N; y1++) {
|
||||
/* Ставим коня на пустую доску */
|
||||
move_n = 1;
|
||||
reset_array(array, N);
|
||||
array[x1][y1] = 1;
|
||||
solve(array, N, x1, y1, &move_n);
|
||||
/* Если другое решение подходит, то выдаем его */
|
||||
if (sum_check(array, N) && is_looped(array, N)) {
|
||||
int difference = array[x][y] - 1;
|
||||
/* Изменяем ходы, будто мы ходили с другого поля */
|
||||
for (int x2 = 0; x2 < N; x2++) {
|
||||
for (int y2 = 0; y2 < N; y2++) {
|
||||
if (array[x2][y2] > difference) {
|
||||
array[x2][y2] -= difference;
|
||||
}
|
||||
else {
|
||||
array[x2][y2] = N * N + array[x2][y2] - difference;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Проверяем замкнутость маршрута */
|
||||
int is_looped(int **array, int N) {
|
||||
int start_x = 0, start_y = 0;
|
||||
int end_x = 0, end_y = 0;
|
||||
/* Ищем */
|
||||
for (int x = 0; x < N; x++ )
|
||||
for (int y = 0; y < N; y++) {
|
||||
if (array[x][y] == 1) {
|
||||
start_x = x;
|
||||
start_y = y;
|
||||
}
|
||||
else if (array[x][y] == N*N) {
|
||||
end_x = x;
|
||||
end_y = y;
|
||||
}
|
||||
}
|
||||
/* Если можем пойти конем из одной в другую, то маршрут замкнут */
|
||||
if ((abs(end_x - start_x) == 1 && abs(end_y - start_y) == 2) || (abs(end_x - start_x) == 2 && abs(end_y - start_y) == 1))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 reset_array(int **array, int N) {
|
||||
for (int i = 0; i < N; i++)
|
||||
for (int j = 0; j < N; j++)
|
||||
array[i][j] = 0;
|
||||
}
|
||||
void print_array(int **array, int N) {
|
||||
for (int i = 0; i < N; i++) {
|
||||
for (int j = 0; j < N; j++)
|
||||
printf("%3d ", array[i][j]);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
Reference in a new issue