728x90
시간 제한 1초, 메모리 제한 256MB
# 조건
- 세현이의 인생의 목표는 1분 1초 모든 순간 수학과 함께 살아가는 것이다.
- 그렇기 때문에 매일 수학을 생각하면서 살아가고 있다.
- 세현이는 밥을 먹을 때도 쌀알의 수를 계산하여 칼로리를 바로 계산하고 한걸음 한걸음 보폭을 계산하여 자신의 활동량을 확인하며 인생의 목표를 실행하며 살아가고 있다.
- 그런 세현이는 매일 학교를 가면서 지나가는 길에도 수학을 적용시키고 싶었다.
- 세현이네 집에서 학교까지 가는 길은 N x N 크기의 바둑판과 같다.
- 그리고 각 블록은 1x1 정사각형으로 구분 지을 수 있다.
- 세현이는 그 블록마다 숫자와 연산자가 존재한다고 생각해서 임의의 숫자와 연산자를 각 블록에 넣어 바둑판을 만들었다.
- 세현이는 학교에서 집으로 가는 경로에서 만나는 숫자와 연산자의 연산 결과의 최댓값과 최솟값을 구하려고 한다.
- 세현이는 항상 자신의 집 (1, 1)에서 학교 (N, N)까지 최단거리로 이동한다.
- 최단거리로 이동하기 위해서는 오른쪽과 아래쪽으로만 이동해야 한다.
- 위와 같이 N = 5 인 5 x 5 바둑판을 만들었다고 해보자.
- 그림 1의 경로를 통해 집(1, 1)에서 학교(N, N)까지 어떻게 연산이 되는지 확인해보자.
- 경로에서 만나는 연산자들의 우선순위는 고려하지 않는다.
- 5 → × → 4 = 20
- 20 → + → 5 = 25
- 25 → ×→ 5 = 125
- 125 → + → 2 = 127
- 그림 1은 최댓값을 가지는 경로이며 127이라는 최댓값을 얻을 수 있다.
- 그리고 위와 같이 연산하여 그림 2의 경로를 통해서 최솟값으로 3을 얻을 수 있다.
- 세현이는 이 길을 걸으면서 최댓값과 최솟값을 암산하다가 교통사고를 당해 현재 인하대학교 병원에 입원했다.
- 아픈 세현이를 위해 최댓값과 최솟값을 구해주자.
입력
- 첫 번째 줄에는 지도의 크기 N이 주어진다. (3 ≤ N ≤ 5, N은 홀수)
- 그 다음 N 줄에는 N개의 숫자 또는 연산자가 빈칸을 사이에 두고 주어지며, 세현이네 집 (1, 1)과 학교 (N, N)는 반드시 숫자로 주어진다.
- 그리고 숫자 다음에는 연산자, 연산자 다음에는 숫자가 나오도록 주어진다.
- 주어지는 숫자는 0이상 5이하의 정수, 연산자는 (‘+’, ‘-’, ‘*’) 만 주어진다.
출력
- 연산 결과의 최댓값과 최솟값을 하나의 공백을 두고 출력한다.
- 연산자 우선순위는 고려하지 않는다.
# 접근 방법
- 지도의 크기가 최대 5이므로 bfs를 돌리며 경로를 저장해준 후 eval을 이용할까 했지만 보안상의 문제로 사용하지 않는다.
- q에 담아줄 내용은 현재 인덱스와 현재까지 저장된 수식의 내용을 넣어준다.
- 또한, q에 담을 때 방문 표시를 한다면 다른 경로의 도착 내용을 알 수 없으므로
- q에서 꺼낼 때 방문 표시를 하여 모든 최단 거리의 경로를 탐색해주어야 한다.
- 도착지에 도착하였다면 문자열을 읽으며 앞에서부터 연산을 해준다.
- +, -, * 는 인덱스 홀 수 번째에 존재하므로 1부터 N-1까지 2씩 이동해준다.
- max_result와 min_result를 갱신해준다.
- 여기서 중요한 점은 max_result도 음수가 될 수 있으므로 초기값으로 충분지 작은 값을 해주어야 한다.
- bfs로 풀어주었지만 dfs로 풀어주는 것이 조금 더 깔끔해 보일 것 같다.
- 또는 dp로 현재 좌표까지의 최대 값을 저장해나가는 것도 하나의 방법이다.
import sys
sys.stdin = open('input.txt')
si = sys.stdin.readline
from collections import deque
def bfs():
q = deque([(0, 0, [arr[0][0]])])
visited = [[False] * N for _ in range(N)]
max_result, min_result = -float('inf'), float('inf')
while q:
si, sj, oper = q.popleft()
visited[si][sj] = True
if (si, sj) == (N-1, N-1):
val = operation(oper)
if val > max_result:
max_result = val
if val < min_result:
min_result = val
for di, dj in [(1, 0), (0, 1)]:
ni, nj = si + di, sj + dj
if check(ni, nj, visited):
q.append((ni, nj, oper + [arr[ni][nj]]))
print(max_result, min_result)
def check(ni, nj, visit):
if 0<=ni<N and 0<=nj<N and not visit[ni][nj]:
return 1
return 0
def operation(nums):
val = int(nums[0])
# 연산기호는 무조건 인덱스 훌수번째에 등장 (1, 3, ..)
for i in range(1, len(nums)-1, 2):
if nums[i] == '+':
val = val + int(nums[i+1])
elif nums[i] == '-':
val = val - int(nums[i+1])
elif nums[i] == '*':
val = val * int(nums[i+1])
return val
N = int(input())
arr = [list(map(str, si().strip().split())) for _ in range(N)]
bfs()
- 또는 dp로 현재 좌표까지의 최대 값을 저장해나가는 것도 하나의 방법이다.
- 현재 좌표에 올 수 있는 방법은 위 또는 왼쪽, 왼쪽 대각 선 위에서 오므로 연산 현재 좌표가 연산 기호일 경우 continue
- 숫자일 경우
- 우선 (왼쪽 대각선 위의 값, 위의 연산기호, 현재 좌표의 값)과 (왼쪽 대각선 위의 값, 왼쪽 연산기호, 현재 좌표의 값)을 계산해서 큰 값과 작은 값을 저장해준다.
- 만약 i와 j가 1보다 크다면 2칸 위의 값, 2칸 왼쪽의 값과도 계산해주어야 한다.
- max(현재 dp의 값, (dp 2칸 왼쪽의 값, 직전의 연산기호, 현재 좌표의 값))을 해주면 된다.
- max(현재 dp의 값, (dp 2칸 위의 값, 직전의 연산기호, 현재 좌표의 값))
- 마찬 가지로 min도 구해주면 된다.
import sys
sys.stdin = open('input.txt')
N = int(sys.stdin.readline())
route = list()
for _ in range(N):
route.append(sys.stdin.readline().split())
max_dp = [[0 for _ in range(N)] for _ in range(N)]
min_dp = [[0 for _ in range(N)] for _ in range(N)]
min_dp[0][0] = max_dp[0][0] = route[0][0]
for i in range(2, N, 2):
max_dp[0][i] = str(eval(max_dp[0][i - 2] + route[0][i - 1] + route[0][i]))
min_dp[0][i] = str(eval(min_dp[0][i - 2] + route[0][i - 1] + route[0][i]))
max_dp[i][0] = str(eval(max_dp[i - 2][0] + route[i - 1][0] + route[i][0]))
min_dp[i][0] = str(eval(min_dp[i - 2][0] + route[i - 1][0] + route[i][0]))
for x in range(1, N):
for y in range(1, N):
if (x + y) % 2 == 1:
continue
max_dp[x][y] = max(eval(max_dp[x - 1][y - 1] + route[x - 1][y] + route[x][y]),
eval(max_dp[x - 1][y - 1] + route[x][y - 1] + route[x][y]))
min_dp[x][y] = min(eval(min_dp[x - 1][y - 1] + route[x - 1][y] + route[x][y]),
eval(min_dp[x - 1][y - 1] + route[x][y - 1] + route[x][y]))
if x > 1:
max_dp[x][y] = max(max_dp[x][y], eval(max_dp[x - 2][y] + route[x - 1][y] + route[x][y]))
min_dp[x][y] = min(min_dp[x][y], eval(min_dp[x - 2][y] + route[x - 1][y] + route[x][y]))
if y > 1:
max_dp[x][y] = max(max_dp[x][y], eval(max_dp[x][y - 2] + route[x][y - 1] + route[x][y]))
min_dp[x][y] = min(min_dp[x][y], eval(min_dp[x][y - 2] + route[x][y - 1] + route[x][y]))
max_dp[x][y] = str(max_dp[x][y])
min_dp[x][y] = str(min_dp[x][y])
print(max_dp[-1][-1], min_dp[-1][-1])
728x90
'ALGORITHM > DFS, BFS, 그래프 탐색' 카테고리의 다른 글
[백준 14442번] 파이썬 - 벽 부수고 이동하기 2 (0) | 2023.09.11 |
---|---|
[백준 16988번] 파이썬 - Baaaaaaaaaduk2(Easy) (0) | 2023.08.31 |
[백준 17086번] 파이썬 - 아기 상어 2 (0) | 2023.08.26 |
[백준 17471번] 파이썬 - 게리맨더링 (0) | 2023.08.26 |
[백준 14226번] 파이썬 - 이모티콘 (0) | 2023.08.22 |