https://programmers.co.kr/learn/courses/30/lessons/67259?language=python3
코딩테스트 연습 - 경주로 건설
[[0,0,0,0,0,0,0,1],[0,0,0,0,0,0,0,0],[0,0,0,0,0,1,0,0],[0,0,0,0,1,0,0,0],[0,0,0,1,0,0,0,1],[0,0,1,0,0,0,1,0],[0,1,0,0,0,1,0,0],[1,0,0,0,0,0,0,0]] 3800 [[0,0,1,0],[0,0,0,0],[0,1,0,1],[1,0,0,0]] 2100 [[0,0,0,0,0,0],[0,1,1,1,1,0],[0,0,1,0,0,0],[1,0,0,1,0,1],[
programmers.co.kr
최종 풀이
GitHub - hwayeon351/Programmers-Algorithms: 프로그래머스 알고리즘 소스 코드 모음
프로그래머스 알고리즘 소스 코드 모음. Contribute to hwayeon351/Programmers-Algorithms development by creating an account on GitHub.
github.com
from collections import deque
dx = [1, 0, -1, 0]
dy = [0, 1, 0, -1]
def bfs(board):
MAX = len(board)*len(board)*600
q = deque()
visit = [[[MAX]*len(board) for _ in range(len(board))] for _ in range(4)]
if board[0][1] == 0:
visit[0][0][1] = 100
q.append([1,0,0,100])
if board[1][0] == 0:
visit[1][1][0] = 100
q.append([0,1,1,100])
for i in range(4):
visit[i][0][0] = 100
while q:
now_x, now_y, now_d, cost = q.popleft()
for i in range(4):
nx = now_x + dx[i]
ny = now_y + dy[i]
if 0<=nx<len(board) and 0<=ny<len(board):
if board[ny][nx]: continue
if i == now_d:
new_cost = cost + 100
else:
new_cost = cost + 600
if visit[i][ny][nx] > new_cost:
visit[i][ny][nx] = new_cost
q.append([nx, ny, i, new_cost])
min_cost = MAX
for i in range(4):
if min_cost > visit[i][-1][-1]: min_cost = visit[i][-1][-1]
return min_cost
def solution(board):
return bfs(board)
풀이 과정
각 위치에 도달하는 최소 비용을 메모이제이션하면서 완전 탐색을 진행하는 방식으로 문제를 풀 수 있다.
이 때, 가장 중요한 점은 각 방향에 대해 해당 위치의 최소 비용을 메모이제이션 해야 한다는 점이다. 이 부분을 간과하면 테스트케이스 25번을 통과 할 수 없다.(아래 오답 노트를 참고하면 왜인지 알 수 있다.)
from collections import deque
#0-우, 1-하, 2-좌, 3-상
dx = [1, 0, -1, 0]
dy = [0, 1, 0, -1]
def bfs(board):
#최대 비용 = 모든 칸에서 코너가 있는 경우로 적용
MAX = len(board)*len(board)*600
#모든 방향에 대하여 N*N에 도달하는 비용의 최솟값을 담을 리스트, visit[direction][y][x]
visit = [[[MAX]*len(board) for _ in range(len(board))] for _ in range(4)]
q = deque()
#시작점으로부터 오른쪽에 있는 칸이 벽이 아닌 경우, (x, y) = (1, 0), direction = 0
if board[0][1] == 0:
#오른쪽 직선 도로에 도로를 설치하므로 비용 = 100원
visit[0][0][1] = 100
q.append([1,0,0,100])
#시작점으로부터 아래쪽에 있는 칸이 벽이 아닌 경우, (x, y) = (0, 1), direction = 1
if board[1][0] == 0:
#왼쪽 직선 도로에 도로를 설치하므로 비용 = 100원
visit[1][1][0] = 100
q.append([0,1,1,100])
#(0, 0)에서의 4방향 모두 비용을 100원으로 초기화
for i in range(4):
visit[i][0][0] = 100
while q:
now_x, now_y, now_d, cost = q.popleft()
for i in range(4):
nx = now_x + dx[i]
ny = now_y + dy[i]
#(nx, ny)가 board 범위 안에 있는 경우
if 0<=nx<len(board) and 0<=ny<len(board):
#(nx, ny)가 벽인 경우, 무시한다
if board[ny][nx]: continue
#방향이 바뀌지 않은 경우, 직선 도로를 설치하므로 100원의 추가 비용 발생
if i == now_d:
new_cost = cost + 100
#방향이 바뀐 경우, 코너가 발생하므로 600원의 추가 비용이 발생
else:
new_cost = cost + 600
#현재 방향의 (nx, ny)까지 도달하는데 드는 이전 비용이 new_cost보다 큰 경우, new_cost 값으로 갱신하고 해당 위치부터 BFS 탐색을 이어나가기 위해 큐에 삽입한다
if visit[i][ny][nx] > new_cost:
visit[i][ny][nx] = new_cost
q.append([nx, ny, i, new_cost])
min_cost = MAX
#4 방향으로 경주로 끝에 접근하는데 드는 비용 중 가장 작은 비용이 min_cost이다
for i in range(4):
if min_cost > visit[i][-1][-1]: min_cost = visit[i][-1][-1]
return min_cost
def solution(board):
return bfs(board)
#시간복잡도 = O(n^2), 공간복잡도 = O(n^2)
오답 노트
풀이시간 2시간 10분
1. DFS
먼저, 깊이 우선 탐색을 통해 모든 경로를 구하여 작은 cost 값으로 answer를 갱신해 나가는 방식으로 풀어봤다. 그랬더니 6개의 테스트케이스에서 시간초과가 떴다. 아무래도 중복 경로를 계속 탐색하기 때문에 시간초과가 난 것으로 예상된다.
(BFS 풀이처럼 메모이제이션을 통해 DFS로 문제를 풀 수 있다고 한다. 추후에 풀어볼 예정이다.)
import sys
sys.setrecursionlimit(20000)
dx = [1, 0, -1, 0]
dy = [0, 1, 0, -1]
def dfs(x, y, d, cost, visit, board):
global answer
if x == len(board)-1 and y == len(board)-1:
if answer == -1: answer = cost
elif cost < answer: answer = cost
return
if answer != -1 and cost >= answer: return
for i in range(4):
nx = x+dx[i]
ny = y+dy[i]
if 0<=nx<len(board) and 0<=ny<len(board):
if visit[ny][nx] == 0 and board[ny][nx] == 0:
visit[ny][nx] = 1
if i == d: dfs(nx, ny, i, cost+100, visit, board)
else: dfs(nx, ny, i, cost+600, visit, board)
visit[ny][nx] = 0
def solution(board):
global answer
answer = -1
visit = [[0]*len(board) for _ in range(len(board))]
for i in range(2):
x = dx[i]
y = dy[i]
if board[y][x] == 1: continue
visit[0][0] = 1
visit[y][x] = 1
dfs(x, y, i, 100, visit, board)
visit[0][0] = 0
visit[y][x] = 0
return answer
2. BFS
다시 BFS로 접근해봤다. N*N visit 배열을 통해 (x, y) 칸에 도달할 때 드는 비용의 최솟값을 갱신해 나가는 방식으로 구현했다. 그런데 25번 테스트에서 실패가 떴다. 왜인지 모르겠어서 한참 헤매다가 예외상황이 있다는 것을 알게 되었다.
- 입력 예제
00000000
10111110
10010000
11000111
11110000
11111110
11111110
11111110
-> 정답: 4500
위 예제를 입력으로 돌려보니 정답은 4900이 나왔다. 직접 종이에 써가며 어떤 상황인지 파악해보니 항상 (x, y)에 도달하는 가장 작은 비용을 선택해야만 최소 비용으로 경로 설정이 가능한 경우가 아닐 수도 있다는 점이다.
즉, 최종 풀이에서처럼 다른 방향으로 (x, y)칸에 도착하는 비용을 체크해줘야 한다. 이 문제의 가장 핵심적인 부분인 것 같다!
from collections import deque
dx = [1, 0, -1, 0]
dy = [0, 1, 0, -1]
def bfs(board):
q = deque()
visit = [[0]*len(board) for _ in range(len(board))]
if board[0][1] == 0:
visit[0][1] = 100
q.append([1,0,0,100])
if board[1][0] == 0:
visit[1][0] = 100
q.append([0,1,1,100])
visit[0][0] = 100
while q:
now_x, now_y, now_d, cost = q.popleft()
for i in range(4):
nx = now_x + dx[i]
ny = now_y + dy[i]
if 0<=nx<len(board) and 0<=ny<len(board):
if board[ny][nx]: continue
if i == now_d:
new_cost = cost + 100
else:
new_cost = cost + 600
if visit[ny][nx] == 0:
visit[ny][nx] = new_cost
q.append([nx, ny, i, new_cost])
else:
if visit[ny][nx] >= new_cost:
visit[ny][nx] = new_cost
q.append([nx, ny, i, new_cost])
return visit[-1][-1]
def solution(board):
return bfs(board)
참고
- 1. 키패드 누르기 -> https://hwayomingdlog.tistory.com/138
Level 1 키패드 누르기 <2020 카카오 인턴십> Python 3
https://programmers.co.kr/learn/courses/30/lessons/67256?language=python3 코딩테스트 연습 - 키패드 누르기 [1, 3, 4, 5, 8, 2, 1, 4, 5, 9, 5] "right" "LRLLLRLLRRL" [7, 0, 8, 2, 8, 3, 1, 5, 7, 6, 2] "l..
hwayomingdlog.tistory.com
Level 2 수식 최대화 <2020 카카오 인턴십> Python 3
https://programmers.co.kr/learn/courses/30/lessons/67257?language=python3 코딩테스트 연습 - 수식 최대화 IT 벤처 회사를 운영하고 있는 라이언은 매년 사내 해커톤 대회를 개최하여 우승자에게 상금을 지급..
hwayomingdlog.tistory.com
- 3. 보석 쇼핑 -> https://hwayomingdlog.tistory.com/136
Level 3 보석 쇼핑 <2020 카카오 인턴십> Python 3
https://programmers.co.kr/learn/courses/30/lessons/67258?language=python3 코딩테스트 연습 - 보석 쇼핑 ["DIA", "RUBY", "RUBY", "DIA", "DIA", "EMERALD", "SAPPHIRE", "DIA"] [3, 7] programmers.co.kr 최..
hwayomingdlog.tistory.com
- 5. 동굴 탐험
'코테 노트 > 프로그래머스' 카테고리의 다른 글
Level 1 실패율 <2019 KAKAO BLIND RECRUITMENT> Python 3 (0) | 2021.09.02 |
---|---|
Level 2 수식 최대화 <2020 카카오 인턴십> Python 3 (0) | 2021.09.02 |
Level 2 거리두기 확인하기 <2021 카카오 인턴십> Python 3 (0) | 2021.08.31 |
Level 3 불량 사용자 <2019 카카오 인턴십> Python 3 (0) | 2021.08.31 |
Level 1 크레인 인형뽑기 게임 <2019 카카오 인턴> Python 3 (0) | 2021.08.30 |