728x90
시간 제한 1초(추가 시간 없음), 메모리 제한 1024MB
# 조건
- 마법사 상어는 파이어볼, 토네이도, 파이어스톰, 물복사버그 마법을 할 수 있다.
- 오늘 새로 배운 마법은 비바라기이다.
- 비바라기를 시전하면 하늘에 비구름을 만들 수 있다.
- 오늘은 비바라기를 크기가 N×N인 격자에서 연습하려고 한다.
- 격자의 각 칸에는 바구니가 하나 있고, 바구니는 칸 전체를 차지한다.
- 바구니에 저장할 수 있는 물의 양에는 제한이 없다.
- (r, c)는 격자의 r행 c열에 있는 바구니를 의미하고, A[r][c]는 (r, c)에 있는 바구니에 저장되어 있는 물의 양을 의미한다.
- 격자의 가장 왼쪽 윗 칸은 (1, 1)이고, 가장 오른쪽 아랫 칸은 (N, N)이다.
- 마법사 상어는 연습을 위해 1번 행과 N번 행을 연결했고, 1번 열과 N번 열도 연결했다.
- 즉, N번 행의 아래에는 1번 행이, 1번 행의 위에는 N번 행이 있고, 1번 열의 왼쪽에는 N번 열이, N번 열의 오른쪽에는 1번 열이 있다.
- 비바라기를 시전하면 (N, 1), (N, 2), (N-1, 1), (N-1, 2)에 비구름이 생긴다.
- 구름은 칸 전체를 차지한다.
- 이제 구름에 이동을 M번 명령하려고 한다.
- i번째 이동 명령은 방향 di과 거리 si로 이루어져 있다.
- 방향은 총 8개의 방향이 있으며, 8개의 정수로 표현한다.
- 1부터 순서대로 ←, ↖, ↑, ↗, →, ↘, ↓, ↙ 이다.
- 이동을 명령하면 다음이 순서대로 진행된다.
- 모든 구름이 di 방향으로 si칸 이동한다.
- 각 구름에서 비가 내려 구름이 있는 칸의 바구니에 저장된 물의 양이 1 증가한다.
- 구름이 모두 사라진다.
- 2에서 물이 증가한 칸 (r, c)에 물복사버그 마법을 시전한다. 물복사버그 마법을 사용하면, 대각선 방향으로 거리가 1인 칸에 물이 있는 바구니의 수만큼 (r, c)에 있는 바구니의 물이 양이 증가한다.
- 이때는 이동과 다르게 경계를 넘어가는 칸은 대각선 방향으로 거리가 1인 칸이 아니다.
- 예를 들어, (N, 2)에서 인접한 대각선 칸은 (N-1, 1), (N-1, 3)이고, (N, N)에서 인접한 대각선 칸은 (N-1, N-1)뿐이다.
- 바구니에 저장된 물의 양이 2 이상인 모든 칸에 구름이 생기고, 물의 양이 2 줄어든다. 이때 구름이 생기는 칸은 3에서 구름이 사라진 칸이 아니어야 한다.
- M번의 이동이 모두 끝난 후 바구니에 들어있는 물의 양의 합을 구해보자.
입력
- 첫째 줄에 N, M이 주어진다.
- 둘째 줄부터 N개의 줄에는 N개의 정수가 주어진다.
- r번째 행의 c번째 정수는 A[r][c]를 의미한다.
- 다음 M개의 줄에는 이동의 정보 di, si가 순서대로 한 줄에 하나씩 주어진다.
출력
- 첫째 줄에 M번의 이동이 모두 끝난 후 바구니에 들어있는 물의 양의 합을 출력한다.
# 접근 방법
- 브루트 포스로 풀어준다.
- 처음 구름이 생성되는 칸을 0, N-1로 치환하여 clouds 리스트에 담아준다.
- 또한 before_clouds set과 di, dj 델타 리스트를 생성해주고 commands를 받아준다.
- 이동 거리 s의 경우 N을 넘어간다면, 중복되는 경로가 생기므로 N으로 나눈 나머지로 변환하여 기록해준다.
- 로직대로 먼저 구름을 이동시킨다.
- di[d], dj[d]에 각각 s만큼 곱한 값을 구름 위치에 더해준다.
- 0보다 작다면 N에서 절댓값만큼 빼주고
- N보다 크다면 N으로 나눈 나머지로 이동시키면서 temp에 추가해준다.
- 모든 이동이 끝났다면 clouds를 []로 초기화 해주고, before_clouds에 temp를 복사해준다.
- before_clouds를 순회하며 물의 양을 1씩 증가시킨 후, cross_check 함수로 4방향의 대각선에 물이 있는지 확인해준다.
- 이 때는 경계를 넘을 수 없으므로 조심하자.
- 물이 있는 칸만큼 증가 시킨 후 모든 칸을 순회하며 물의 양이 2 이상이고 before_clouds에 들어있지 않다면 clouds에 추가해준다.
set 자료 구조를 활용한 이유는 list 보다 in => 존재 여부를 확인하는데 있어 걸이는 tat time이 작기 때문이다..!
import sys
sys.stdin = open('input.txt')
input = sys.stdin.readline
import copy
'''
14:20 시작 - 14:54 solve
0번과 n-1번 연결
비바라기 시전 => (N-1, 0), (N-1, 1), (N-2, 0), (N-2, 1)에 비구름
M번 이동
왼, 왼쪽위, 위, 오른쪽위, 오른쪽, 오른쪽아래, 아래, 왼아래
1. 모든 구름이 D방향 S칸 이동
2. 구름이 있는 칸에 물 1 증가
3. 구름 제거
4. 물이 증가한 칸에 물복사 => 대각선 방향으로 거리가 1인 칸에 물이 있는 바구니의 수만큼 R, C의 물의 양이 증가
이 때는 경계 넘어가는건 X
5. 물의 양이 2이상인 모든 칸에 구름 새이고, 물 2 줄어든다.
이 때, 구름이 생기는 칸은 3에서 구름이 사라진 칸이 아니어야 한다.
'''
def clouds_move(d, s):
global clouds, before_clouds
temp = set()
for ci, cj in clouds:
ci += di[d] * s
cj += dj[d] * s
if ci < 0:
ci = N - abs(ci)
elif ci >= N:
ci %= N
if cj < 0:
cj = N - abs(cj)
elif cj >= N:
cj %= N
temp.add((ci, cj))
clouds = []
before_clouds = temp
def increase_clouds():
global clouds, before_clouds, arr
for ci, cj in before_clouds:
arr[ci][cj] += 1
for ci, cj in before_clouds:
num = cross_check(ci, cj)
arr[ci][cj] += num
def cross_check(ci, cj):
global arr
cnt = 0
for d in [2, 4, 6, 8]:
ni, nj = ci + di[d], cj + dj[d]
if 0<=ni<N and 0<=nj<N and arr[ni][nj] > 0:
cnt += 1
return cnt
def make_clouds():
for i in range(N):
for j in range(N):
if arr[i][j] >= 2 and (i, j) not in before_clouds:
clouds.append((i, j))
arr[i][j] -= 2
N, M = map(int, input().split())
arr = [list(map(int, input().split())) for _ in range(N)]
clouds = [(N-1, 0), (N-1, 1), (N-2, 0), (N-2, 1)]
before_clouds = set()
di, dj = [0, 0, -1, -1, -1, 0, 1, 1, 1], [0, -1, -1, 0, 1, 1, 1, 0, -1]
commands = []
for _ in range(M):
d, s = map(int, input().split())
s %= N
commands.append((d, s))
for d,s in commands:
clouds_move(d, s)
increase_clouds()
make_clouds()
result = 0
for a in arr:
result += sum(a)
print(result)
728x90
'ALGORITHM > Brute Force' 카테고리의 다른 글
[백준 20002번] 파이썬 - 사과나무 (0) | 2024.02.22 |
---|---|
[백준 17135번] 파이썬 - 캐슬 디펜스 (1) | 2023.10.24 |
[백준 19699번] 파이썬 - 소-난다! (1) | 2023.10.11 |
[백준 5568번] 파이썬 - 카드 놓기 (0) | 2023.09.13 |
[백준 2422번] 파이썬 - 한윤정이 이탈리아에 가서 아이스크림을 사먹는데 (3) | 2023.08.27 |