JB의 이모저모

[BOJ 1022🥇3] 소용돌이 예쁘게 출력하기 (Python) 본문

알고리즘/백준

[BOJ 1022🥇3] 소용돌이 예쁘게 출력하기 (Python)

J B 2024. 9. 13. 16:15

https://www.acmicpc.net/problem/1022

문제

크기가 무한인 정사각형 모눈종이가 있다. 모눈종이의 각 정사각형은 행과 열의 쌍으로 표현할 수 있다.

이 모눈종이 전체를 양의 정수의 소용돌이 모양으로 채울 것이다. 일단 숫자 1을 0행 0열에 쓴다. 그리고 나서 0행 1열에 숫자 2를 쓴다. 거기서 부터 소용돌이는 반시계 방향으로 시작된다. 다음 숫자는 다음과 같이 채우면 된다.

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

이 문제는 위와 같이 채운 것을 예쁘게 출력하면 된다. r1, c1, r2, c2가 입력으로 주어진다. r1, c1은 가장 왼쪽 위 칸이고, r2, c2는 가장 오른쪽 아래 칸이다.

예쁘게 출력한다는 것은 다음과 같이 출력하는 것이다.

  1. 출력은 r1행부터 r2행까지 차례대로 출력한다.
  2. 각 원소는 공백으로 구분한다.
  3. 모든 행은 같은 길이를 가져야 한다.
  4. 공백의 길이는 최소로 해야 한다.
  5. 모든 숫자의 길이(앞에 붙는 공백을 포함)는 같아야 한다.
  6. 만약 수의 길이가 가장 길이가 긴 수보다 작다면, 왼쪽에서부터 공백을 삽입해 길이를 맞춘다.

입력

첫째 줄에 네 정수 r1, c1, r2, c2가 주어진다.

출력

r2 - r1 + 1개의 줄에 소용돌이를 예쁘게 출력한다.

제한

  • -5 000 ≤ r1, c1, r2, c2 ≤ 5,000
  • 0 ≤ r2 - r1 ≤ 49
  • 0 ≤ c2 - c1 ≤ 4

예제 입력 1 

-3 -3 2 0

예제 출력 1 복사

37 36 35 34
38 17 16 15
39 18  5  4
40 19  6  1
41 20  7  8
42 21 22 23

예제 입력 2 

-2 2 0 3

예제 출력 2 

13 30
12 29
11 28

예제 입력 3 

-1 -2 -1 1

예제 출력 3 

18  5  4  3

예제 입력 4 

0 0 0 0

예제 출력 4 

1

 

⭕ CODE

import sys

sys.stdin = open('input.txt')

input = sys.stdin.readline

from pprint import pprint

r1, c1, r2, c2 = map(int, input().split())

# x축 길이 y축 길이
x = r2 - r1 + 1
y = c2 - c1 + 1


# (-a, -a)
# 1 5 17 37 65 101
#  4 12 20 28 36

# 0 -> 1 + (4*0)
# 1 -> 1 + (4*1)
# 2 -> 5 + (4*3) = 1 + (4*1) + (4*3) = 1 + 4 * 4
# 3 -> 17 + (4*5) =  1 + (4*1) + (4*3) + (4*5) = 1 + 4* 9
# 4 -> 37 + (4*7) = 1 + (4*1) + (4*3) + (4*5)+ (4*7) = 1 + 4* 16
# 1 + 4*n^2

# (-a,a)

# 1 5 17 37 65 = 4*n^2 + 1
# 1 3 13 31 57 = 4*n^2 - 2*n + 1
# 0 2  4  6  8

# (a,-a)

# 1 7 21 43 73 = 4*n^2 + 2*n + 1
# 1 5 17 37 65 = 4*n^2 + 1
# 0 2 4  6  8

# (a,a)

# 1 9 25 49 81 = 4*n^2 + 4*n + 1
# 1 3 13 31 57 = 4*n^2 - 2*n + 1
# 0 6 12 18 24

# 구역을 나누자
# ▽ # (-a,-a)에서 빼주자 1구역
# ▷ # (-a,-a)에서 더해주자 2구역
# △ # (a,a)에서 빼주자 # 3구역
# ◁ # (-a,a)에서 빼주자 # 4구역


arr = [[0] * y for _ in range(x)]

max_len = 0
for i in range(x):
    for j in range(y):
        # 모눈종이에 나오는 a,b 좌표
        a = i + r1
        b = j + c1

        if abs(a) == abs(b):
            # (a,a)
            if a > 0 and b > 0:
                arr[i][j] = 4 * (a ** 2) + 4 * a + 1
            # (a,-a)
            if a > 0 and b < 0:
                arr[i][j] = 4 * (a ** 2) + 2 * a + 1
            # (-a,-a)
            if a < 0 and b < 0:
                arr[i][j] = 4 * (abs(a) ** 2) + 1
            # (-a,a)
            if a < 0 and b > 0:
                arr[i][j] = 4 * (abs(a) ** 2) - 2 * abs(a) + 1
            if a == 0 and b == 0:
                arr[i][j] = 1
        else:
            # ▽ 모양이라면
            if a < 0 and abs(a) > abs(b):
                arr[i][j] = 4 * (abs(a) ** 2) + 1 - (b - a)
            # ▷ 모양이라면
            if b < 0 and abs(a) < abs(b):
                arr[i][j] = 4 * (abs(b) ** 2) + 1 + (a - b)
            # △ 모양이라면
            if a > 0 and abs(a) > abs(b):
                arr[i][j] = 4 * (a ** 2) + 4 * a + 1 - (a - b)
            # ◁ 모양이라면
            if b > 0 and abs(a) < abs(b):
                arr[i][j] = 4 * (b ** 2) - 2 * b + 1 - (b + a)
        if len(str(arr[i][j])) > max_len:
            max_len = len(str(arr[i][j]))

for i in range(x):
    for j in range(y):
        if len(str(arr[i][j])) < max_len:
            # max_len 길이만큼 오른쪽에 공백을 채운다.
            print(str(arr[i][j]).rjust(max_len,' '), end=' ')
        else:
            print(arr[i][j], end=' ')
    print()

✏️ Comment

(0,0) 인  1을 기준으로 (-1,-1), (-2,-2), (-3,-3), (-a,-a) 대각선의 규칙을 구하면 
1, 5 , 17, 37, 65, 101  … 은 4*n^2 + 1

(0,0) 인  1을 기준으로 (-1,1), (-2,2), (-3,3) (-a,a) 대각선의 규칙을 구하면 
1, 3, 13, 31, 57   은  4*n^2 - 2*n + 1

(0,0) 인  1을 기준으로 (1,-1), (2,-2), (3,-3), (a,-a) 대각선의 규칙을 구하면 
1, 7, 21, 43, 73 ... 은 4*n^2 + 2*n + 1

(0,0) 인  1을 기준으로 (1,1), (2,2), (3,3), (a,a) 대각선의 규칙을 구하면
1, 9, 25, 49, 81 ... 은 4*n^2 + 4*n + 1


여기서
▽ 모양의 숫자는 (-a,-a)에서 y축 거리만큼 빼주기
▷ 모양의 숫자는 (-a,-a)에서 x축 거리만큼 더해주기
△ 모양의 숫자는 (a,a)에서 y축 거리만큼 빼주기
◁ 모양의 숫자는 (-a,a)에서 x축 거리만큼 빼주기

위와 같이 규칙을 구해서 구현하였다.

문제 조건 중 아래와 같은 조건이 있었는데
모든 숫자의 길이(앞에 붙는 공백을 포함)는 같아야 한다.만약 수의 길이가 가장 길이가 긴 수보다 작다면, 왼쪽에서부터 공백을 삽입해 길이를 맞춘다.
이 조건을 충족시키느라 시간이 오래 걸렸다.