풀이
문제에서 주어진대로 구현하면 되는 문제다. 하나 주의할 것은 전체 크기만큼 2차원 리스트를 만들고 출력 범위 부분만 출력하게 되면 메모리 초과가 발생하게 된다. 전체 크기만큼 2차원 리스트가 있다고 가정하고 소용돌이를 돌리되, 실제 리스트는 출력 범위 크기로 만들어야 한다.
문제에 나온 예제 1번을 보면 위와 같이 전체 크기만큼 소용돌이를 돌리지만 실제 리스트는 빨간색 네모에 해당하는 부분으로 만들고 해당 범위에 들어왔을 때 리스트의 값을 수정해 주면 된다.
소용돌이가 동작하는 과정은 (오른쪽, 위쪽, 왼쪽, 아래쪽)과 같은 순서로 진행된다. 처음 (0, 0)에 1을 채워놓고 소용돌이를 돌리면 다음과 같은 규칙을 발견할 수 있다.
- 오른쪽으로 1칸, 위쪽으로 1칸 진행
- 왼쪽으로 2칸, 아래쪽으로 2칸 진행
- 오른쪽으로 3칸, 위쪽으로 3칸 진행
- 왼쪽으로 4칸, 아래쪽으로 4칸 진행
- ..........
- 마지막 오른쪽으로 진행되는 과정은 가장 왼쪽 아래칸부터 가장 오른쪽 아래 칸 까지 진행 (위의 예에서 (3, -3)에서 (3, 3)까지)
위의 규칙에 맞춰서 각 방향의 for문을 해당하는 횟수만큼 진행시키면 된다.
소용돌이를 돌릴 때 현재 좌표는 전체 크기로 가정하고 조정한다. 마이너스 좌표는 제대로 사용할 수 없기 때문에 모눈종이의 사이즈에 맞춰 조정이 필요하다. 입력으로 주어지는 r1, c1, r2, c2중 절대값이 가장 큰 값으로 size를 설정하여 좌표를 조정한다. 위의 예에서 -3, -3, 2, 0이 주어졌으므로 size는 3이 되고 모눈종이의 실제 좌표에 +size를 해주면 된다(위의 예에서 (0, 0)은 (3, 3)이 된다).
반시계 방향으로 진행하는 과정에서 현재 좌표가 출력해야 하는 범위에 해당할 때 리스트의 값을 설정하면 된다. 이때, 가장 길이가 긴 문자열을 설정해놓고 마지막에 출력할 때 해당 길이에 맞춰서 앞에 공백이 필요할 경우 추가해서 출력하면 된다.
코드
# 소용돌이 함수. size: size만큼 소용돌이가 진행된다, dCnt: 상하좌우 각각 dCnt만큼 진행된다.
def solve(size, dCnt):
# 오른쪽, 위쪽, 왼쪽, 아래쪽 순으로 진행된다.
for _ in range(size):
toRight(dCnt)
toUp(dCnt)
dCnt += 1 # up에서 left로 갈 때 횟수가 1 증가한다.
toLeft(dCnt)
toDown(dCnt)
dCnt += 1 # down에서 right로 갈 때 횟수가 1 증가한다.
toRight(size * 2) # 마지막에 right가 한 번 더 진행된다.
# 오른쪽 진행 함수
def toRight(dCnt):
global sy, num, strLen
for _ in range(dCnt):
sy += 1 # 행은 그대로, 열은 1 증가
num += 1
if r1 <= sx <= r2 and c1 <= sy <= c2: # 현재 좌표가 출력해야 하는 범위에 해당할 경우
strLen = max(strLen, len(str(num))) # 길이를 갱신하고
board[sx-r1][sy-c1] = str(num) # 현재 좌표를 출력 리스트의 좌표로 조정하여 값을 할당한다
# 위쪽 진행 함수
def toUp(dCnt):
global sx, num, strLen
for _ in range(dCnt):
sx -= 1 # 행은 1 감소, 열은 그대로
num += 1
if r1 <= sx <= r2 and c1 <= sy <= c2: # 현재 좌표가 출력해야 하는 범위에 해당할 경우
strLen = max(strLen, len(str(num))) # 길이를 갱신하고
board[sx-r1][sy-c1] = str(num) # 현재 좌표를 출력 리스트의 좌표로 조정하여 값을 할당한다
# 왼쪽 진행 함수
def toLeft(dCnt):
global sy, num, strLen
for _ in range(dCnt):
sy -= 1 # 행은 그대로, 열은 1 감소
num += 1
if r1 <= sx <= r2 and c1 <= sy <= c2: # 현재 좌표가 출력해야 하는 범위에 해당할 경우
strLen = max(strLen, len(str(num))) # 길이를 갱신하고
board[sx-r1][sy-c1] = str(num) # 현재 좌표를 출력 리스트의 좌표로 조정하여 값을 할당한다
# 아래쪽 진행 함수
def toDown(dCnt):
global sx, num, strLen
for _ in range(dCnt):
sx += 1 # 행은 1 증가, 열은 그대로
num += 1
if r1 <= sx <= r2 and c1 <= sy <= c2: # 현재 좌표가 출력해야 하는 범위에 해당할 경우
strLen = max(strLen, len(str(num))) # 길이를 갱신하고
board[sx-r1][sy-c1] = str(num) # 현재 좌표를 출력 리스트의 좌표로 조정하여 값을 할당한다
if __name__ == '__main__':
r1, c1, r2, c2 = map(int, input().split())
# r1, c1, r2, c2중 절대값이 가장 큰 값으로 사이즈를 설정한다.
# size가 3일 경우 (0, 0)을 기준으로 상하좌우로 3칸씩이 더 필요하다는 것을 의미한다.
tmp1 = max(abs(r1), abs(r2))
tmp2 = max(abs(c1), abs(c2))
size = max(tmp1, tmp2)
board = [['0' for _ in range(c2-c1+1)] for _ in range(r2-r1+1)] # 출력에 필요한 크기만큼만 2차원 리스트 생성
r1 += size # r1, c1, r2, c2에 size만큼을 더해서 출력 범위에 맞게 설정한다.
c1 += size
r2 += size
c2 += size
strLen = 1 # 출력해야 할 문자열 중 길이가 가장 긴 문자열의 길이
sx, sy = size, size # 전체 사이즈를 기준으로 (0, 0)을 알맞게 조정
num = 1 # 배열에 입력될 숫자.
if r1 <= sx <= r2 and c1 <= sy <= c2: # (sx, sy)가 출력되는 범위에 해당할 경우 값을 할당한다.
board[sx-r1][sy-c1] = str(num) # 출력 리스트의 인덱스에 맞추기 위해 현재 좌표에 각각 -r1, -c1을 해준다.
solve(size, 1) # 소용돌이 함수
# 출력
for i in range(r2-r1+1):
for j in range(c2-c1+1):
tmp = ''
if len(board[i][j]) < strLen: # 현재 좌표의 문자열의 길이가 strLen보다 짧을 경우
tmp = ' ' * (strLen - len(board[i][j])) # 필요한 만큼의 공백 추가
print(tmp + board[i][j], end=' ')
print()
'Algorithm > Baekjoon' 카테고리의 다른 글
2437. 저울 (Python) (0) | 2022.03.06 |
---|---|
1339. 단어 수학 (Python) (0) | 2022.03.04 |
1202. 보석 도둑 (Python) (0) | 2022.02.28 |
1647. 도시 분할 계획 (Python) (0) | 2022.02.28 |
4195. 친구 네트워크 (Python) (0) | 2022.02.28 |
댓글