💻 문제: 달팽이
- 문제 링크: https://www.acmicpc.net/problem/1913
- 알고리즘 분류: 구현(Implementation), 시뮬레이션(Simulation)
문제 소개 🧐
홀수 N이 주어졌을 때, 1부터 N²까지의 자연수를 달팽이 모양으로 N×N 표에 채우고, 특정 숫자의 좌표를 찾는 문제다.
시간 제한 | 메모리 제한 | 제출 | 정답 | 맞힌 사람 | 정답 비율 |
---|---|---|---|---|---|
2 초 | 128 MB | 24832 | 10898 | 8115 | 45.414% |
입력 📝
- 첫째 줄에 홀수인 자연수 N(3 ≤ N ≤ 999)이 주어진다.
- 둘째 줄에는 위치를 찾고자 하는 N² 이하의 자연수가 하나 주어진다.
출력 📤
- N개의 줄에 걸쳐 표를 출력한다.
- N+1번째 줄에는 입력받은 자연수의 좌표를 출력한다. (1-based index)
나의 풀이 ✨
Idea
달팽이가 움직이는 방향(아래, 오른쪽, 위, 왼쪽)에 따라 순차적으로 숫자를 채워나가는 시뮬레이션 방식을 사용했다.
- N x N 크기의 2차원 배열을 0으로 초기화한다.
- 가장 큰 수인
N*N
부터 시작하여 1까지 숫자를 줄여가며 배열에 채운다. - 움직이는 방향은
dir
변수를 이용해 0(아래), 1(오른쪽), 2(위), 3(왼쪽)으로 관리한다. - 한 방향으로의 채우기가 끝나면
dir
을 1 증가시켜 방향을 바꾼다. - 한 바퀴(아래-오른쪽-위-왼쪽)가 모두 돌면, 탐색 범위를 안쪽으로 한 칸씩 좁힌다. (
start += 1
,end -= 1
) - 숫자를 채울 때마다 찾고자 하는
target
값인지 확인하고, 맞다면 좌표를 저장한다.
Code
import sys
N = int(sys.stdin.readline().rstrip())
target = int(sys.stdin.readline().rstrip())
def is_target(num):
global target
if num == target:
return True
else:
return False
def snail():
global N
result = [[0 for _ in range(N)] for _ in range(N)]
start = 0
end = N-1
num = N ** 2
dir = 0
pos = (0,0)
while num > 0:
dir %= 4
if dir == 0: # 아래로
for r in range(start, end+1):
result[r][start] = num
if is_target(num):
pos = (r+1, start+1)
num -= 1
elif dir == 1: # 오른쪽
for c in range(start+1, end+1):
result[end][c] = num
if is_target(num):
pos = (end+1, c+1)
num -= 1
elif dir == 2: # 위로
for r in range(end-1, start-1, -1):
result[r][end] = num
if is_target(num):
pos = (r+1, end+1)
num -= 1
elif dir == 3: # 좌로
for c in range(end-1, start, -1):
result[start][c] = num
if is_target(num):
pos = (start+1, c+1)
num -= 1
# 끝났으니까 start, end 값 조정
start += 1
end -= 1
dir += 1
return pos, result
answer_pos, answer_list = snail()
for ans in answer_list:
print(*ans)
print(*answer_pos)
Result
- 결과: 성공! 🎉
- 주어진 로직에 따라 N*N부터 1까지 숫자를 채워나가며 달팽이 배열을 완성했다.
배운 점 및 개선할 부분 🤔
- 시뮬레이션의 정석: 이 문제는 방향과 경계를 정확하게 관리하는 것이 핵심인 대표적인 시뮬레이션 문제다.
dir
변수로 방향을 제어하고,start
와end
변수로 배열의 채울 범위를 좁혀나가는 방식이 유효했다. - 좌표계 변환: 문제의 좌표는 1-based index이지만, 배열은 0-based index를 사용하므로 값을 저장하고 출력할 때
+1
을 해주는 등 주의가 필요하다. - 시작 값: 숫자를 큰 값부터 채우는 방식으로 구현했다. 반대로 1부터 채워나갈 수도 있는데, 그 경우 시작 위치와 방향 전환 로직이 달라질 것이다. 어떤 방식이든 일관성 있게 구현하는 것이 중요하다.
- 파이썬 내장 식별자: 생각해보니
dir
은 파이썬의 내장 식별자였다. 더 큰 시스템을 만들 때를 대비해서라도 내장 식별자를 의식적으로 피하는 습관을 들여야겠다.
빙글빙글, 달팽이 배열을 만들다 보면 방향 감각과 경계 처리 능력이 쑥쑥 자란다.
⁂