[백준][1022] 소용돌이 예쁘게 출력하기

suhan0304·2023년 11월 1일
0

백준

목록 보기
6/53
post-thumbnail

문제

  • (0, 0)의 1을 시작으로 반시계 방향으로 정사각형 모눈종이가 1씩 증가하면서 채워진다.
  • 이 때 r1, c1, r2, c2가 입력으로 주어진다.
    - r1, c2은 가장 왼쪽 위 칸
    • r2, c2는 가장 오른쪽 아래 칸
  • (r1, c1)부터 (r2, c2)까지 예쁘게 출력한다.
  • 예쁘게 출력한다는 것은 다음과 같다.
    	1. 출력은 r1행부터 r2행까지 차례대로 출력
    	2. 각 원소는 공백으로 구분
    	3. 모든 행은 같은 길이
    	4. 공백의 길이는 최소한
    	5. 모든 숫자의 길이(앞에 붙는 공백을 포함)은 동일
    	6. 수의 길이가 가장 길이가 긴 수보다 작다면 왼쪽에서부터 공백을 삽입해 길이를 맞춤

입력

  • r1, c1, r2, c2가 주어진다.

출력

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

풀이

  • 이 문제의 표를 보고나서 가장 먼저 떠오른 것은 공식을 만들어야겠다고 생각했다. 숫자가 규칙성 있게 반시계 방향으로 돌아가기 때문에 r과 c의 좌표값을 토대로 공식을 세울 수만 있다면 어떤 r, c값이 들어와도 금방 답을 구할 수 있을 것이다.
  • 만약 (0,0)에서부터 반시계방향대로 배열을 모두 만든다면 r, c의 값이 커지면 커질수록 모눈종이(리스트)의 크기는 기하급수적으로 커질 것이고 실행 시간 초과, 기억 공간 낭비와 같은 문제가 발생할 것이다.
  • 따라서 일정한 규칙을 이용해 최대한 빠르게 원하는 값을 찾을 수 있도록 한다.
  • 다음과 같이 모눈종이를 두 부분으로 구분할 수 있다.

  • 이렇게 두 부분으로 나눈 이유는 값은 반시계 방향으로 1씩 증가하면서 진행하기 때문에, 정사각형으로 잘랐을때 원소 하나만 구한다면 값을 구하기 쉬운데 반시계 방향으로 1씩 증가하다가 빨간색 원으로 표시해둔 숫자를 기준으로 갑자기 값이 크게 변화하기 때문에 이렇게 나눴다.
    - 이 때 하늘색 기준선의 아랫 부분은 r ≥ c를 만족하는 영역, 하늘색 기준선의 윗 부분은 r < c를 만족하는 영역이다.
  • 같은 정사각형 내에서 특정 좌표에서 숫자 하나의 값을 구해서 해당 값과 특정 좌표 r, c의 차이를 구한다면 값을 구할 수 있을 것이다.

  • 다음과 같이 (0,0)을 중심으로 하는 같은 길이의 정사각형을 보면, 하늘색 기준선의 아랫 부분은 파란색으로 숫자를 이용해서 값을 구하고, 하늘색 기준선의 윗 부분은 파란색으로 표시한 숫자를 이용해서 값을 구할 수 있다. 따라서 녹색 정사각형 내부의 원소들의 위치의 값들을 구할 땐 파란색으로 표시한 숫자를 구해 r과 c값 차이를 빼서 값을 구할 수 있다.

  • (r, c)에 들어갈 숫자를 구해보자.

  1. 기준이 될 숫자의 값을 구한다.
    r, c의 절댓값 중 큰 값을 n이라고 하자
(n,n)의 값 = ((max(r,c)2)+1)2\displaystyle\\(n, n)의\ 값\ =\ ((max(|r|, |c|) * 2)+1)^2
(n,n+1)의 값 = 4(max(r,c)2\displaystyle\\(-n, -n+1)의\ 값\ =\ 4 * (max(|r|, |c|)^2
  1. 이 때 기준이 될 숫자의 좌표는 고정이다. 따라서 r, c값의 차이를 이용해 실제 들어갈 값을 다음과 같이 구할 수 있다.
(r,c)의 값 = ((max(r,c)2)+1)2(nr+nc)\displaystyle\\(r, c)의\ 값\ =\ ((max(|r|, |c|) * 2)+1)^2 - (|n-r| + |n-c|)
(r,c)의 값 = 4(max(r,c)2(nr+n+1c)\displaystyle\\(r, c)의\ 값\ =\ 4 * (max(|r|, |c|)^2 - (|-n-r| + |-n+1-c|)
  1. 위와 같은 공식을 이용해 좌표 (r, c)의 값들을 바로 계산할 수 있다.

위 공식을 기반으로 좌표에 해당하는 값을 계산하고 문제의 조건에 맞춰 다음과 같이 '예쁘게'출력해줄 수 있다.

import math

digit = int(math.log10(digit)) + 1

for i in ans:
    for j in i:
        print(str(j).rjust(digit), end=" ")
    print()

이 때 자리수를 구해야 왼쪽에 공백을 필요한 만큼 삽입해서 정렬이 가능하므로 math 모듈의 log10을 이용해 자리수를 구할 수 있다. rjust(int, char) 함수는 문자열을 오른쪽 정렬해주는데 int 길이만큼 부족한 부분을 char로 채운다. char을 따로 지정해주지 않으면 공백으로 기본값이 주어진다.


코드

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

ans = [[0 for _ in range(c2 - c1 + 1)] for _ in range(r2 - r1 + 1)]

digit = 0
for r in range(r2 - r1 + 1):
   for c in range(c2 - c1 + 1):
       R = r1 + r
       C = c1 + c

       ans[r][c] = [R, C]

       n = max(abs(R), abs(C))
       if R >= C:
           ans[r][c] = (((n * 2) + 1) ** 2) - (abs(n - R) + abs(n - C))
       else:
           ans[r][c] = 4 * (n**2) - (abs((-n) - R) + abs((-n + 1) - C))
       if ans[r][c] > digit:
           digit = ans[r][c]

import math

digit = int(math.log10(digit)) + 1

for i in ans:
   for j in i:
       print(str(j).rjust(digit), end=" ")
   print()
profile
Be Honest, Be Harder, Be Stronger

0개의 댓글