C 언어로 3×3 마방진 퍼즐 푸는 방법 Python

⚡ 스마트 요약

마법 정사각형 퍼즐은 n x n 격자 안에 연속된 숫자를 배열하여 모든 행, 열, 대각선의 합이 모두 같은 값(마법 상수)을 내도록 하는 퍼즐로, 오락 수학 및 알고리즘적 사고력을 기르는 고전적인 연습 문제입니다.

  • 🔢 마법 상수 공식: 일반적인 n차 마방진의 경우, 마방진의 합은 n(n²+1)/2이며, 이는 3차 마방진의 경우 15, 7차 마방진의 경우 175를 산출합니다.
  • 🧩 샴 방식: 홀수 순서의 마방진은 맨 위 행의 가운데에 1을 놓고, 겹침 및 충돌 규칙을 처리하면서 오른쪽 위로 이동함으로써 생성됩니다.
  • 📐 정사각형 변형: 마법진은 일반 마법진, 준마법진, 단순 마법진, 완전 마법진으로 분류되며, 각 변형은 합이 마법 상수와 일치해야 하는 조건에 따라 정의됩니다.
  • 실제 구현 사례: 같은 C++ Python 프로그램은 O(n²) 보조 공간을 사용하여 O(n²) 시간 내에 임의의 홀수 차수 정사각형을 구성합니다.
  • 🧪 단계별 데모: 자세한 3x3 배치 과정을 통해 9가지 배치 각각이 행, 열, 대각선 규칙을 만족하는 방법을 보여줍니다.

마법의 정사각형이란 무엇일까요?

마방진은 특별한 방식으로 숫자가 배열된 정사각형 행렬입니다. 각 행, 각 열, 그리고 두 개의 주대각선의 합이 항상 같도록 숫자가 배치됩니다. 마방진은 오락 수학에서 사용되는 간단한 논리 퍼즐입니다.

마법의 사각형 예:

매직 스퀘어

위 그림은 3차 마방진을 보여줍니다. 모든 대각선, 행, 열의 합은 15입니다. 다음 절에서는 이처럼 일정한 합계가 어떻게 생성되는지 설명합니다.

마법진의 작동 원리

n차 마방진은 n²개의 양의 정수로 이루어진 n×n 행렬입니다. 행 또는 열의 개수를 행렬의 차수라고 합니다.

일반적인 마방진 퍼즐은 홀수 차수를 가지며 1부터 n²까지의 정수를 사용합니다. 모든 행, 열, 대각선의 합이 같아야 하므로 이 값을 마법의 합 또는 마법의 상수라고 합니다. 이 상수는 n에만 의존합니다. n차 마방진의 마법의 합을 구하는 공식은 다음과 같습니다.

매직스퀘어 작품

3차 마방진을 생각해 봅시다. 그러면 마방진의 합은 다음과 같습니다.

매직스퀘어 작품

매직스퀘어 작품

이 공식은 산술적인 원리를 설명하지만, 이 퍼즐은 오랜 문화적 역사를 가지고 있어 기억에 남는 이름을 갖게 되었습니다.

그것들을 마법이라고 부르는 이유는 무엇일까요?

고대 수학자들은 흥미로운 숫자 조합에 매료되었는데, 마방진도 그중 하나였다. 가장 오래된 기록은 기원전 190년경 중국에서 발견되었다.

연구에 따르면 고대 일본, 인도, 아라비아에서 마법 정사각형 퍼즐의 흔적이 발견되었습니다. 전설에 따르면 이러한 배열은 마법의 세계와 연관되었고, 그 이름이 그대로 굳어졌습니다. 민속 설화 외에도 수학자들은 각 정사각형을 구별하는 형식적인 범주를 정의했습니다.

매직스퀘어의 종류

수학에는 마방진의 여러 변형이 있습니다.

  • 일반 마방진: 첫 번째 n²개의 자연수를 포함합니다.
  • 세미 매직 스퀘어: 행과 열의 합만 마법의 상수와 일치합니다.
  • 심플 매직 스퀘어: 행, 열, 그리고 두 개의 주요 대각선의 합이 마법의 상수와 같습니다.
  • 가장 완벽한 마법진: 두 가지 추가 속성을 가진 일반 마방진입니다. 행렬의 모든 2x2 부분 정사각형의 합은 2(n²+1)이고, n/2 칸 떨어진 두 숫자의 합은 n²+1입니다.

추가적인 속성에 따라 더 많은 범주가 존재합니다. 이 튜토리얼에서 "마법 정사각형"이라는 용어가 별도의 설명 없이 사용될 때는 홀수 차수의 일반 단순 마법 정사각형을 의미합니다.

마법 정사각형을 생성하는 알고리즘

홀수 차수의 마방진을 생성하는 고전적인 알고리즘인 샴 방식은 다음과 같습니다.

  • 첫 번째 숫자(1)는 위치 (n/2, n-1)에 저장되며, 여기서 첫 번째 좌표는 행 인덱스이고 두 번째 좌표는 열 인덱스입니다. 이후 단계에서는 이 위치를 (x, y)라고 부릅니다.
  • 다음 숫자는 (x-1, y+1) 위치에 놓입니다. 해당 위치가 유효하지 않으면 다음 규칙을 적용합니다.
    1. 행 인덱스가 -1이면 n-1로, 열 인덱스가 n이면 0으로 래핑합니다.
    2. 계산된 위치에 이미 숫자가 포함되어 있으면 행을 1만큼 증가시키고 열을 2만큼 감소시킵니다.
    3. 행이 -1이고 열이 n인 경우 새 위치는 (0, n-2)입니다.

참고 : 이 알고리즘은 홀수 차수의 유효한 마방진만 생성합니다. 결과는 처음 n²개의 자연수를 포함하는 일반 마방진입니다. 동일한 n에 대해 여러 개의 유효한 해가 존재할 수 있습니다.

1부터 9까지의 숫자를 사용하는 3차 순서의 간단한 예시를 통해 규칙이 더 명확해집니다.

3x3 정사각형에서 작동 방식

적용 연산 위의 단계는 다음과 같습니다.

단계 1) 첫 번째 숫자(1)는 (3/2, 3-1) 또는 (1, 2)에 배치됩니다. 이후 단계에서는 x = 1 및 y = 2로 설정합니다.

마방진 생성 알고리즘

단계 2) 나머지 숫자의 위치는 다음과 같이 계산됩니다.

2번 위치:

다음 숫자는 (x-1, y+1) 또는 (0, 3)으로 이동해야 하는데 이는 유효한 위치가 아닙니다. 규칙 (a)에 따라 열이 0으로 순환되어 (0, 0)이 됩니다. x = 0, y = 0으로 설정합니다.

마방진 생성 알고리즘

3번 위치:

숫자 3은 (x-1, y+1) 또는 (-1, 1)에 있어야 하는데, 이는 유효한 위치가 아닙니다. 규칙 (a)에 따라 행은 n-1(즉, 2)로 순환합니다. 따라서 숫자 3은 (2, 1)로 이동합니다. x = 2, y = 1로 설정합니다.

마방진 생성 알고리즘

4번 위치:

숫자 4는 (x-1, y+1) 또는 (1, 2)에 있어야 하는데, 이는 유효하지만 이미 1이 포함되어 있습니다. 규칙 (b)에 따라 새로운 위치는 (1+1, 2-2) 또는 (2, 0)입니다. x = 2, y = 0으로 설정합니다.

마방진 생성 알고리즘

5번 위치:

숫자 5은 (x-1, y+1) 또는 (1, 1)에 있어야 하며, 이는 유효한 빈 위치입니다. x = 1, y = 1로 설정하세요.

마방진 생성 알고리즘

6번 위치:

숫자 6은 (x-1, y+1) 또는 (0, 2)에 있어야 하며, 이는 유효한 빈 위치입니다. x = 0, y = 2로 설정하세요.

마방진 생성 알고리즘

7번 위치:

숫자 7은 (x-1, y+1) 또는 (-1, 3)에 있어야 하는데 이는 유효하지 않습니다. 규칙 (c)에 따라 새로운 위치는 (0, n-2) 또는 (0, 1)입니다. x = 0, y = 1로 설정합니다.

마방진 생성 알고리즘

8번 위치:

숫자 8은 (x-1, y+1) 또는 (-1, 2)에 있어야 하는데 이는 유효하지 않습니다. 규칙 (a)에 따라 행이 2로 순환되어 (2, 2)가 됩니다. x = 2, y = 2로 설정합니다.

마방진 생성 알고리즘

9번 위치:

숫자 9는 (x-1, y+1) 또는 (1, 3)에 있어야 하는데 이는 유효하지 않습니다. 규칙 (a)에 따라 열이 0으로 순환되어 (1, 0)이 됩니다.

마방진 생성 알고리즘

모든 칸이 채워지면 동일한 논리가 의사 코드로 직접 변환됩니다.

매직 스퀘어의 의사 코드

Begin
    Declare an array of size n*n
    Initialize the array to 0
    Set row = n/2
    Set column = n-1
    For all number i: from 1 to n*n
        If the row = -1 and column = n
            row = 0
            column = n-2
        Else
            If row = -1
                row = n-1
            If column = n
                column = 0
        If the position already contains a number
            decrement column by 2
            increment row by 1
            continue until the position is not 0
        Else
            put the number i into the calculated position
            increment i
        Increment column value
        Decrement row value
End

의사 코드는 컴파일 언어와 인터프리터 언어에 직접적으로 대응하며, 이는 다음 그림에 나와 있습니다. C++ Python.

C++ Code 매직 스퀘어의 경우

입력:

/*
A C/C++ program for generating odd order magic squares
*/
#include <bits/stdc++.h>
using namespace std;

void GenerateMagicSquare(int n)
{
    int magic[n][n];
    //initializing the array
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
            magic[i][j] = 0;
    //setting row and column value
    int i = n / 2;
    int j = n - 1;
    for (int k = 1; k <= n * n;)
    {
        //checking condition (c)
        if (i == -1 && j == n)
        {
            j = n - 2;
            i = 0;
        }
        else
        {
            //checking condition (a)
            if (j == n)
                j = 0;
            if (i < 0)
                i = n - 1;
        }
        //checking condition (b)
        if (magic[i][j])
        {
            j -= 2;
            i++;
            continue;
        }
        else
        {
            //placing the number into the array
            magic[i][j] = k;
            k++;
        }
        //for the next number setting (i-1, j+1)
        j++;
        i--;
    }
    //printing the matrix
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
            cout << magic[i][j] << "  ";
        cout << endl;
    }
}
int main()
{
    //This code works for only odd numbers
    int n = 7;
    cout<<"The magic sum is " << n*(n*n+1)/2 <<endl;
    GenerateMagicSquare(n);
    return 0;
}

예제 출력:

The magic sum is 175

20  12  4  45  37  29  28
11  3  44  36  35  27  19
2  43  42  34  26  18  10
49  41  33  25  17  9  1
40  32  24  16  8  7  48
31  23  15  14  6  47  39
22  21  13  5  46  38  30

The Python 아래 버전은 동일한 행 및 열 규칙을 사용합니다.

Python Code 매직 스퀘어의 경우

def GenerateMagicSquare(n):
    #initializing the array
    magic = [[0 for x in range(n)]
                for y in range(n)]
    #setting row and column value
    i = n // 2
    j = n - 1
    k = 1
    while k <= (n * n):
        #checking condition (c)
        if i == -1 and j == n:
            j = n - 2
            i = 0
        else:
            #checking condition (a)
            if j == n:
                j = 0
            if i < 0:
                i = n - 1
        #checking conditon (b)
        if magic[i][j]:
            j = j - 2
            i = i + 1
            continue
        else:
            #placing the number into the array
            magic[i][j] = k
            k = k + 1
        #for the next number setting (i-1, j+1)
        j = j + 1
        i = i - 1
    #printing the matrix
    for i in range(0, n):
        for j in range(0, n):
            print('%2d ' % (magic[i][j]),end='')
            if j == n - 1:
                print()
#This code works for only odd numbers
n = 7
print("The magic sum is ",n * (n * n + 1) // 2, "\n")
GenerateMagicSquare(n)

예제 출력:

The magic sum is  175

20 12  4 45 37 29 28
11  3 44 36 35 27 19
 2 43 42 34 26 18 10
49 41 33 25 17  9  1
40 32 24 16  8  7 48
31 23 15 14  6 47 39
22 21 13  5 46 38 30

두 구현 방식은 동작 방식이 동일하므로 비용을 쉽게 비교할 수 있습니다.

복잡성 분석

  • 공간 복잡성 : 마방진은 n x n 배열에 저장되므로 공간 복잡도는 O(n²)입니다.
  • 시간 복잡성 : 생성기는 두 개의 중첩 루프를 사용합니다. 바깥쪽 루프는 n번 실행되고, 안쪽 루프도 n번 실행되므로 전체 시간 복잡도는 O(n²)입니다.

자주 묻는 질문

1부터 9까지의 숫자가 포함된 일반적인 3x3 마방진의 경우, 마법 상수는 15입니다. 모든 행, 열, 그리고 주대각선의 합은 15가 되어야 하는데, 이는 n(n²+1)/2 공식(n=3)에서 성립합니다.

아니요. 이 튜토리얼에서 보여주는 샴 방식은 홀수 차수의 마방진에만 적용됩니다. 짝수 차수의 마방진은 다른 알고리즘을 사용해야 하며, 예를 들어 n이 4로 나누어 떨어지는 이중 짝수 마방진이나 n이 4k+2인 단일 짝수 마방진 구성에는 각각 다른 규칙이 사용됩니다.

생성기는 n x n 행렬을 채우므로 시간 복잡도와 공간 복잡도 모두 O(n²)입니다. 각 셀은 일정한 횟수만큼 방문되며, 저장 공간은 정확히 n²개의 정수입니다. 따라서 이 알고리즘은 일반적인 오락용 게임 크기에 효율적입니다.

유전 알고리즘, 시뮬레이티드 어닐링, 제약 조건 만족 해결사 등의 AI 기술은 짝수 차수, 부분 마방진, 소수만으로 구성된 마방진 또는 기하학적 마방진과 같은 추가 제약 조건이 있는 변형을 포함하여 폐쇄형 방법이 적용되지 않는 경우에도 유효한 마방진을 찾을 수 있습니다.

마방진은 조합 최적화, 강화 학습 에이전트 및 신경망 탐색의 벤치마크 문제로 사용됩니다. 연구자들은 마방진을 이용하여 구조화된 이산 공간에서 휴리스틱, 메타휴리스틱 및 AI 플래너를 테스트하는데, 이는 해를 검증하기는 쉽지만 마방진의 개수를 세는 것은 여전히 ​​미해결된 수학적 문제이기 때문입니다.

이 게시물을 요약하면 다음과 같습니다.