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