728x90
반응형
골드 Ⅰ
https://www.acmicpc.net/problem/17143
📄 문제
- 낚시왕이 상어 낚시를 하는 곳은 크기가 R×C인 격자판으로 나타낼 수 있다.
- 격자판의 각 칸은 (r, c)로 나타낼 수 있다.
- r은 행, c는 열이고, (R, C)는 아래 그림에서 가장 오른쪽 아래에 있는 칸이다.
- 칸에는 상어가 최대 한 마리 들어있을 수 있다.
- 상어는 크기와 속도를 가지고 있다.
- 낚시왕은 처음에 1번 열의 한 칸 왼쪽에 있다.
- 다음은 1초 동안 일어나는 일이며, 아래 적힌 순서대로 일어난다.
- 낚시왕이 오른쪽으로 한 칸 이동한다.
- 낚시왕이 있는 열에 있는 상어 중에서 땅과 제일 가까운 상어를 잡는다. 상어를 잡으면 격자판에서 잡은 상어가 사라진다.
- 상어가 이동한다.
- 상어는 입력으로 주어진 속도로 이동하고, 속도의 단위는 칸/초이다.
- 상어가 이동하려고 하는 칸이 격자판의 경계를 넘는 경우에는 방향을 반대로 바꿔서 속력을 유지한 채로 이동한다.
- 낚시왕은 가장 오른쪽 열의 오른쪽 칸에 이동하면 이동을 멈춘다.
- 상어가 이동을 마친 후에 한 칸에 상어가 두 마리 이상 있을 수 있다. 이때는 크기가 가장 큰 상어가 나머지 상어를 모두 잡아먹는다.
낚시왕이 상어 낚시를 하는 격자판의 상태가 주어졌을 때, 낚시왕이 잡은 상어 크기의 합을 구해보자.
💡 아이디어
- 구현 문제이다. 주어진 문제의 순서에 따라 구현하면 된다.
- 낚시왕이 같은 열에 있는 상어 중에서 땅과 제일 가까운 상어를 잡는 함수가 필요하다.
- 낚시왕이 잡은 상어 크기의 합을 저장할 변수도 필요하다.
- 상어가 이동하는 함수가 필요하다.
- 상어가 이동을 후, 한 칸에 상어가 두 마리 이상 있을 때 크기가 가장 큰 상어가 나머지 상어를 모두 잡아먹는 함수 또는 알고리즘이 필요하다.
- 따라서, 아래의 순서로 알고리즘을 구현하면 된다.
- 낚시왕이 전체 열을 순차적으로 탐색한다. (이동한다.)
- 열을 이동할 때마다, 해당 열을 탐색하여 땅과 제일 가까운 상어를 잡아 크기를 저장한다.
- 낚시 후, 전체 상어를 차례대로 주어진 방향과 속도로 이동시킨다.
- 이동 중, 격자판의 경계를 만나면 방향을 반대로 바꿔서 계속 이동한다.
- 이동한 상어는 새로운 격자판의 이동 위치에 속도, 방향, 크기를 저장한다.
- 열을 차례대로 탐색하면서 2,3,4,5번을 반복한다.
- 모든 상어가 이동한 후 또는 이동 중 일 때, 새로운 격자판의 같은 칸에 이동한 상어가 두 마리 이상 존재하면 가장 큰 상어만 남긴다.
상어를 이동 시키는 방법과 같은 칸에 가장 큰 상어만 남기는 방법을 두가지로 풀이했다.
상어를 이동 시키는 방법 (새로운 격자판에 위치 저장)
- 반복문을 활용하여, 해당 속도와 방향으로 한 칸씩 이동시킨다.
- 한 칸씩 이동하면서 경계를 만나면 방향을 바꿔 이동한다.
- 이동이 끝난 위치를 미리 계산하여 바로 저장한다. ✅
- 바뀐 위치와 방향을 격자판의 개수와 속도를 이용하여 미리 계산한다.
가장 큰 상어만 남기는 방법
- 모든 상어의 이동이 끝난 후
- 모든 상어를 차례대로 이동시킨다.
- 새로운 격자판에 이동한 상어를 저장한다.
- 모든 상어의 이동이 끝난 후 새로운 격자판을 전체 탐색한다.
- 같은 칸에 상어가 두 마리 이상일 때 가장 큰 상어만 남기고 나머지 상어는 제거한다.
- 상어가 이동 중 일 때 ✅
- 모든 상어를 차례대로 이동시킨다.
- 새로운 격자판에 이동한 상어를 저장한다.
- 저장 전에, 해당 칸에 이미 이동한 상어가 있는지 확인한다.
- 상어가 없으면 그대로 저장하고
- 상어가 있으면 크기를 비교해 큰 상어로 바꿔 저장한다.
📝 문제 풀이 (Code)
최종 코드 ( 실행시간 264ms, 메모리 127052 KB, PyPy3 )
- 상어를 이동시킬 때, 이동이 끝난 위치를 미리 계산하여 새로운 격자판에 바로 저장한다.
- 상어가 이동할 때, 새로운 격자판에 이미 이동한 상어가 존재하면 상어의 크기를 비교하여 큰 상어만 남긴다.
import sys
input = sys.stdin.readline
def move_shark():
# 이동한 상어 저장
ocean = [[False]*c for _ in range(r)]
# 전체 상어 이동
for x in range(r):
for y in range(c):
if sea[x][y]:
s, d, z = sea[x][y]
nx = x + di[d] * s
ny = y + dj[d] * s
# 위아래
if d == 1 or d == 2:
quota = nx // (r-1)
remainder = nx % (r-1)
# 같은 방향
if quota % 2 == 0:
nx = remainder
# 방향 전환
else:
d = boundary[d]
nx = (r - 1) - remainder
# 좌우
else:
quota = ny // (c-1)
remainder = ny % (c-1)
# 같은 방향
if quota % 2 == 0:
ny = remainder
# 방향 전환
else:
d = boundary[d]
ny = (c - 1) - remainder
# 큰 상어만 남기기
if not ocean[nx][ny] or ocean[nx][ny][2] < z:
ocean[nx][ny] = (s, d, z)
return ocean
def catch_shark(j):
global sea
# 행 탐색
for i in range(r):
if sea[i][j]:
# 상어를 잡는다.
s, d, z = sea[i][j]
sea[i][j] = False
return z
return 0
# 격자판의 크기 R, C와 상어의 수 M
r, c, m = map(int, input().split())
sea = [[False]*c for _ in range(r)]
# d가 1인 경우는 위, 2인 경우는 아래, 3인 경우는 오른쪽, 4인 경우는 왼쪽
di = [0, -1, 1, 0, 0]
dj = [0, 0, 0, 1, -1]
boundary = {1:2, 2:1, 3:4, 4:3}
for _ in range(m):
# (r, c)는 상어의 위치, s는 속력, d는 이동 방향, z는 크기
rr, cc, s, d, z = map(int, input().split())
sea[rr-1][cc-1] = (s, d, z)
fishing = 0
for j in range(c):
# 낚시
fishing += catch_shark(j)
# 상어 이동
sea = move_shark()
print(fishing)
처음 코드 ( 실행시간 2876 ms, 메모리 224452 KB, PyPy3)
- 상어를 이동 시킬때, 반복문을 활용하여 해당 속도와 방향으로 한 칸씩 이동시킨다.
- 모든 상어의 이동이 끝난 후, 격자판을 탐색하여 같은 칸에 2마리 이상 존재할 때 큰 상어만 남긴다.
import sys
input = sys.stdin.readline
def move_shark():
ocean = [[[] for _ in range(c)] for _ in range(r)]
# 전체 상어 이동
for row in range(r):
for col in range(c):
if sea[row][col]:
z, s, d = sea[row][col][0]
x = row
y = col
go = 0
# 상어 속도 만큼 이동
while go < s:
nx = x + di[d]
ny = y + dj[d]
if 0 <= nx < r and 0 <= ny < c:
x, y = nx, ny
go += 1
# 벽과 충돌, 방향전환
else:
d = boundary[d]
continue
ocean[x][y].append((z, s, d))
return ocean
def shark_eat():
global sea
for row in range(r):
for col in range(c):
# 한 칸에 상어가 2마리 이상 있는 경우
if 1 < len(sea[row][col]):
sea[row][col].sort(reverse=True)
sea[row][col] = [sea[row][col][0]]
def catch_shark(j):
global sea
# 행 탐색
for i in range(r):
if sea[i][j]:
# 상어를 잡는다.
z, s, d = sea[i][j].pop()
return z
return 0
# 격자판의 크기 R, C와 상어의 수 M
r, c, m = map(int, input().split())
sea = [[[] for _ in range(c)] for _ in range(r)]
# d가 1인 경우는 위, 2인 경우는 아래, 3인 경우는 오른쪽, 4인 경우는 왼쪽을 의미한다.
di = [0, -1, 1, 0, 0]
dj = [0, 0, 0, 1, -1]
boundary = {1:2, 2:1, 3:4, 4:3}
for _ in range(m):
# (rr, cc)는 상어의 위치, s는 속력, d는 이동 방향, z는 크기이다.
rr, cc, s, d, z = map(int, input().split())
sea[rr-1][cc-1].append((z, s, d))
fishing = 0
for j in range(c):
# 낚시
fishing += catch_shark(j)
# 상어가 이동한다.
sea = move_shark()
# 큰 상어가 먹는다
shark_eat()
print(fishing)
두 번째 코드 ( 실행시간 2804 ms, 메모리 223112 KB, PyPy3 )
처음 코드와 다른 점은 상어가 이동을 마친 후에 한 칸에 두 마리 이상 있을 때, 가장 큰 상어를 남기는 방법을 다르게 구현하였다. (각 상어가 이동할 때, 전체 상어 이동 후)
- 상어가 이동할 때, 이미 이동한 상어가 존재하면 상어의 크기를 비교하여 큰 상어만 남긴다. (이동 중에 비교)
더보기
import sys
input = sys.stdin.readline
def move_shark():
ocean = [[[] for _ in range(c)] for _ in range(r)]
# 전체 상어 이동
for row in range(r):
for col in range(c):
if sea[row][col]:
s, d, z = sea[row][col][0]
x = row
y = col
go = 0
# 상어 속도 만큼 이동
while go < s:
nx = x + di[d]
ny = y + dj[d]
# 맵 내부에서 이동하는 경우
if 0 <= nx < r and 0 <= ny < c:
x, y = nx, ny
go += 1
# 벽과 충돌하는 경우, 방향전환
else:
d = boundary[d]
continue
# 큰 상어만 남기기
if not ocean[x][y] or ocean[x][y][0][2] < z:
ocean[x][y] = [(s, d, z)]
return ocean
def catch_shark(j):
global sea
# 행 탐색
for i in range(r):
if sea[i][j]:
# 상어를 잡는다.
s, d, z = sea[i][j].pop()
return z
return 0
# 격자판의 크기 R, C와 상어의 수 M
r, c, m = map(int, input().split())
sea = [[[] for _ in range(c)] for _ in range(r)]
# d가 1인 경우는 위, 2인 경우는 아래, 3인 경우는 오른쪽, 4인 경우는 왼쪽을 의미한다.
di = [0, -1, 1, 0, 0]
dj = [0, 0, 0, 1, -1]
boundary = {1:2, 2:1, 3:4, 4:3}
for _ in range(m):
# (rr, cc)는 상어의 위치, s는 속력, d는 이동 방향, z는 크기이다.
rr, cc, s, d, z = map(int, input().split())
sea[rr-1][cc-1].append((s, d, z))
fishing = 0
for j in range(c):
# 낚시
fishing += catch_shark(j)
# 상어가 이동한다.
sea = move_shark()
print(fishing)
728x90
반응형
'Algorithm Solving > Baekjoon' 카테고리의 다른 글
[백준] 14891 톱니바퀴 (파이썬) (0) | 2023.09.19 |
---|---|
[백준] 13460 구슬 탈출 2 (파이썬) (0) | 2023.09.14 |
[백준] 7662 이중 우선순위 큐 (파이썬) (0) | 2023.09.12 |
[백준] 1300 K번째 수 (파이썬) (0) | 2023.09.11 |
[백준] 15685 드래곤 커브 (파이썬) (0) | 2023.09.07 |