Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

파이썬으로 체스 말이 모든 위치에 도달하는 최소 이동 횟수 구하기


문제 개요

체스판과 특수한 나이트 말 K가 하나 있다고 가정해 봅시다. 이 말은 체스판 위에서 L자 모양으로 움직입니다. 말이 (x1, y1) 위치에 있을 때 (x2, y2)로 이동한다면, 그 움직임은 다음과 같이 표현할 수 있습니다.

x2 = x1 ± a ; y2 = y1 ± b 또는 x2 = x1 ± b ; y2 = y1 ± a (단, a와 b는 정수)

우리가 구해야 할 것은 이 체스 말이 (0, 0) 위치에서 출발하여 체스판의 (n-1, n-1) 위치에 도달하기 위해 필요한 최소 이동 횟수입니다. 어떤 위치가 도달할 수 없다면 -1을 표시하고, 도달 가능하다면 실제 이동 횟수를 반환합니다. 결과는 n-1줄로 출력되며, 각 줄 i에는 j마다 필요한 최소 이동 횟수를 나타내는 n-1개의 정수가 포함됩니다.

예를 들어 입력이 n = 6이라면 출력은 다음과 같습니다.

파이썬으로 체스 말이 모든 위치에 도달하는 최소 이동 횟수 구하기

5  4  3  2  5
4 -1  2 -1 -1
3  2 -1 -1 -1
2 -1 -1 -1 -1
5 -1 -1 -1  1


위 그림은 5x5 체스판에서 나이트가 (3, 3) 위치에 있을 때 가능한 이동 경로를 보여줍니다.

출력의 첫 번째 줄에는 말이 (1,1)부터 (1,5)까지 각 위치에 도달하는 데 필요한 최소 이동 횟수가 담깁니다. 이어지는 줄들도 마찬가지로 각각의 i와 j 값에 대한 최소 이동 횟수를 순서대로 나타냅니다.

풀이 접근 방법

이 문제는 너비 우선 탐색(BFS)을 활용하면 효율적으로 해결할 수 있습니다. 각 이동 규칙 (i, j)에 대해 시작점 (0, 0)부터 목표점 (n-1, n-1)까지의 최단 거리를 BFS로 계산하고, 이동 규칙의 대칭성을 활용해 중복 계산을 줄이는 것이 핵심입니다.

path_search() 함수 정의

i, j, n 세 값을 인자로 받는 함수를 정의합니다.

  • temp_list := (-1, -1) 쌍으로 초기화된 새로운 맵

  • queue_positional := (0, 0) 쌍으로 초기화된 새로운 리스트

  • ver := [(i, j), (-i, j), (i, -j), (-i, -j), (j, i), (j, -i), (-j, i), (-j, -i)] — 8방향 이동 벡터

  • 큐(queue_positional)가 빌 때까지 반복합니다.

    • current_element := 큐의 첫 번째 원소를 꺼냄

    • ver의 각 이동 벡터 element에 대해 다음을 수행합니다.

      • x := element[0] + current_element[0]

      • y := element[1] + current_element[1]

      • 좌표가 체스판 범위 내(-1 < x < n, -1 < y < n)이고 아직 방문하지 않았다면(temp_list[x, y]가 (-1, -1)인 경우):

        • temp_list[x, y]에 현재 위치(이전 칸)를 기록하고, (x, y)를 큐 끝에 추가합니다.

        • 만약 x가 n-1이고 y가 n-1이라면 목표 지점에 도달한 것이므로, temp_list를 따라 출발점 (0, 0)까지 역추적하면서 이동 횟수를 세어 반환합니다.

  • 목표 지점에 도달할 수 없다면 -1을 반환합니다.

메인 함수에서의 처리

  • board := -1로 초기화된 새로운 맵

  • i를 1부터 n 미만까지, j를 1부터 i 미만까지 반복합니다.

    • board[i, j]가 아직 계산되지 않았다면(-1인 경우) path_search(i, j, n)를 호출하고, 대칭성을 활용해 board[j, i]에도 같은 값을 저장합니다.

    • 만약 (n - 1)이 i로 나누어떨어진다면 board[i, i] := (n - 1) / i 로 직접 계산합니다.

  • 마지막으로 i를 1부터 n 미만까지 반복하면서 각 행의 board[i, j] 값을 공백으로 구분해 출력하고, 각 행의 마지막 값 board[i, n - 1]을 줄바꿈과 함께 출력합니다.

소스 코드 (Python)

아래 구현 예시를 통해 더 자세히 이해해 보겠습니다.

from collections import defaultdict
def path_search(i, j, n):
    temp_list = defaultdict(lambda: (-1,-1))
    queue_positional = [(0, 0)]
    ver = [(i, j), (-i, j), (i, -j), (-i, -j), (j, i), (j, -i), (-j, i), (-j, -i)]
    while len(queue_positional) > 0:
        current_element = queue_positional.pop(0)
        for element in ver:
            x = element[0] + current_element[0]
            y = element[1] + current_element[1]
            if -1 < x < n and -1 < y < n and temp_list[x, y] == (-1,-1):
                temp_list[x, y] = current_element
                queue_positional.append((x, y))
                if x == n - 1 and y == n - 1:
                    count_var = 1
                    while temp_list[x,y]!=(0,0):
                        count_var += 1
                        x, y = temp_list[x,y]
                    return count_var
    return -1

def solve(n):
    board = defaultdict(lambda: -1)
    for i in range(1, n):
        for j in range(1, i):
            if board[i, j] == -1:
                board[i, j] = path_search(i, j, n)
                board[j, i] = board[i, j]
        if (n - 1) % i == 0:
            board[i, i] = (n - 1) / i

    for i in range(1, n):
        for j in range(1, n - 1):
            print(int(board[i, j]), end = ' ')
        print(int(board[i, n - 1]))

solve(6)

입력

6

출력

5  4  3  2  5
4 -1  2 -1 -1
3  2 -1 -1 -1
2 -1 -1 -1 -1
5 -1 -1 -1  1