2022 현대 모비스 알고리즘 경진 대회 예선 문제 리뷰
Problem
Table of Contents
공통 사항
Python3
기준, 수행시간은 10초
- 이에 따라, 계산 가능한 최대 횟수는 약
2억번
Dead or Arrive 설명
- 각 차량은
v
의 속도와 w
의 내구도를 가짐
- 속도가 다른 차량은 모두 결승선 통과
- 속도가 같은 경우, 내구도가 가장 높은 차량만 결승선을 통과
- 속도와 내구도가 모두 같은 경우, 차량 번호가 가장 큰 차량만 결승선 통과
- 첫 번째 줄에 차량의 숫자
N
이 입력
- 두 번째 줄부터
N
줄만큼 각 차량의 v
, w
가 주어진다.
N
은 최대 2,000,000
까지 주어지며, v
는 최대 1,000
, w
는 최대 1,000,000,000
까지 주어진다.
- Mars Killaz의 차량 중 결승선에 들어온 차량의 번호의 합을 출력하시오.
Dead or Arrive 풀이
- 일반적인 구현 문제로 보인다.
- 우선 순위가 1차가 속도, 2차가 내구도, 3차가 차량 번호로 지정되도록 뽑으면 되는 문제
- 처음에 한참, 같은 속도의 차량을 뽑아내서, 그 다음에 같은 내구도의 차량을 뽑은 다음… 이런 식으로 진행하려고 했더니, 정신아 아득해졌다..
- 어찌됐든, 속도 중복이 없는 내구도가 가장 높거나 번호가 가장 높은 차량을 뽑는 것이므로,
Dictionary
를 이용하면 좋을 것 같았다.
- 현재 입력된 속도가
Dictionary
에 존재하는 지 확인한 후, 없다면, 단순 추가
- 있다면, 기존 값과 비교를 통해 w가 높으면 교체, w도 같다면, 차량 숫자를 비교하여 높으면 교체와 같은 형식으로 진행하였다.
- 코드는 다음과 같다.
# -*- coding: utf-8 -*-
# Dead or Arrive 문제
import sys
input = sys.stdin.readline
N = int(input())
vehicles = []
for i in range(1, N + 1):
v, w = map(int, input().split())
vehicles.append((v, w, i))
s_vehicles = sorted(vehicles, key=lambda x: x[0])
speed_dict = dict()
for v, w, i in s_vehicles:
if not v in speed_dict:
speed_dict[v] = (w, i)
elif w > speed_dict[v][0]:
speed_dict[v] = (w, i)
elif w == speed_dict[v][0]:
if i > speed_dict[v][1]:
speed_dict[v] = (w, i)
result = 0
for (w, i) in speed_dict.values():
result += i
print(result)
주차 시스템 설명
- 현대 백화점 주차장의 특별 주차 시스템
- 주차장은 0, 1, 2로 구분
- 0은 자동차가 없음
- 1은 자동차가 있음
- 2는 자동차는 없지만, 장애인 전용 주차 공간
- 주차장이 주어지면, 1로 나누어진 곳을 기준으로, 여러 개의 구역이 나누어진다.
- 나누어진 구역은 0인 칸의 개수만큼
+1점
, 2인 칸의 개수만큼 -2점
을 하여, 구역의 점수를 계산한다.
- 여러 개의 구역 중 가장 높은 점수를 구하시오.
- 첫 번째 줄에 주차장의 크기인
N
, M
이 주어짐.
- 두 번째 줄부터
N
줄에 걸쳐, M
개의 숫자가 주어집니다. 각각의 값은 주차장의 상태를 나타냅니다.
주차 시스템 풀이
- 결국 모든 주차 구역에 대해
BFS
or DFS
를 이용하여, 탐색하고, 탐색한 범위의 값들을 기준에 맞게 합산하여, 저장해두었다가, 모든 탐색이 끝난 후, 최대 값을 출력하면 된다.
BFS
or DFS
의 구현이 익숙하다면, 쉽게 해결할 수 있다.
- 최대한 간단하게 코드를 작성을 했는데, 테스트 케이스 2개가 자꾸 해결이 안되었다.
- 네트워크랑 PC 성능의 문제가 영향이 없다고는 하는데, 간혹 있는 경우가 있어서 다시 진행해볼 예정이다.
- 코드는 다음과 같다.
# -*- coding: utf-8 -*-
import sys
from collections import deque
input = sys.stdin.readline
N, M = map(int, input().split())
parking = [list(map(int, input().split())) for _ in range(N)]
dxy = [[1, 0], [0, 1], [-1, 0], [0, -1]]
area_score = 0
for i in range(N):
for j in range(M):
if parking[i][j] == 1:
continue
Q = deque([(i, j)])
if parking[i][j] == 0:
tmp_score = 1
else:
tmp_score = -2
parking[i][j] = 1
while Q:
now_x, now_y = Q.popleft()
for dx, dy in dxy:
tmp_x = now_x + dx
tmp_y = now_y + dy
if not (0 <= tmp_x < N and 0 <= tmp_y < M):
continue
if parking[tmp_x][tmp_y] != 1:
Q.append((tmp_x, tmp_y))
if parking[tmp_x][tmp_y] == 0:
tmp_score += 1
else:
tmp_score += -2
parking[tmp_x][tmp_y] = 1
if area_score < tmp_score:
area_score = tmp_score
print(area_score)
ADAS 시스템 설명
- 2차원 좌표평면으로 가상 주행 환경을 구성
- $0 <= a < W$, $0 <= b < H$인 (a, b) 좌표의 점은
일반 점
, P- 점
, 점 S
, 점 E
로 표현
- 가상 주행 시스템은
점 S
에서 시작하여 점 E
로 이동하며, 점 E
에 도착하면 주행이 종료
- 주행 과정에서 ADAS 시스템은 다음 조건을 따라 이동
- (a, b)에서 상하좌우 4개의 방향 중, 방문한 적 없는 점을 이동 후보 목록에 추가 (좌표 평면 바깥이면 제외)
- 다음 방문할 점은 아래 우선 순위에 따라서 결정
점 E
는 우선 순위가 가장 높음
P- 점
은 그 다음으로 높음
일반점
이 가장 낮음
- 우선 순위가 동일한 점이 여러 개 있다면, a가 작은 것이 우선, a도 같다면 b가 작은 것이 우선 순위가 높다.
- 주행 중 위험 점수는
0점
에서 시작하여, 다음 규칙에 따라 위험 점수가 증가
점 S
와 점 E
는 위험 점수 증가 없음
일반 점
은 해당 점을 중심으로 $3 \times 3$ 크기 안에서 자신을 제외한 P- 점
의 개수만큼 위험 점수가 증가
P- 점
은 일반 점
과 동일한 방법으로 측정한 후, -3점
만큼 위험 점수가 증가
- ADAS 시스템이 목적지에 도착하면 종료하며, 위험 점수를 출력
W
와 H
는 최대 1,000
까지 주어진다.
- 첫째 줄에
W
, H
가 주어지며, 둘째 줄부터 W
줄에 걸쳐 S
, E
, P
, 0
의 문자열이 주어진다.
ADAS 시스템 풀이
- 우선 이동 후보에 넣은 후, 우선 순위에 따라 먼저 꺼내야하는 문제이다.
- 이걸 우선 순위를 다 찾아서 꺼내면… $O(N)$이 될 것이다.
- 우상단에서 우하단까지 이동한다면, 모든 점을 거쳐서 이동하며, 최대 $N^2$의 이동을 한다.
- 최대 계산량은 $O(N^3)$이므로,
1,000,000,000
번의 연산이 필요하다.
10초
의 시간으로 연산할 수 있는 양은 200,000,000
번이므로, 어림도 없다.
- 그렇다면, 우선 순위 큐를 쓴다면 어떨까?
- 일반 큐의 탐색은 $O(N)$이지만, 우선 순위 큐의 탐색은 $O(logN)$이다.
- 따라서 계산량이 $O(N^3)$에서 $O(N^2logN)$으로 바뀌며, 약
10,000,000
번으로 해결이 되는 엄청난 성능을 볼 수 있다.
- 그렇다면, 우선 순위에 맞춰서 잘 넣고, 잘 찾아주는 우선 순위 큐만 잘 구현한다면, 어렵지 않게 맞출 수 있을 것 같다.
- 하지만, 이상하게도 5개의 테스트 케이스를 통과할 수 없었다. 왤까…. 아시면 댓글 부탁드립니다.
- 코드는 다음과 같다.
# -*- coding: utf-8 -*-
import sys
import heapq
input = sys.stdin.readline
W, H = map(int, input().split())
virtual_env = [input().strip() for _ in range(W)]
def is_valid_coordinate(x, y):
if 0 <= x < W and 0 <= y < H:
return True
return False
def find_S(virtual_env):
for x, value in enumerate(virtual_env):
y = value.find('S')
if y == -1:
continue
return (x, y)
dx = [-1, 0, 1, 0]
dy = [0, -1, 0, 1]
hq = []
S_x, S_y = find_S(virtual_env)
heapq.heappush(hq, (0, S_x, S_y))
visited = set()
visited.add(S_x * H + S_y)
def calc_point(x, y):
tmp_score = 0
if virtual_env[x][y] == 'S' or virtual_env[x][y] == 'E':
return 0
if virtual_env[x][y] == 'P':
tmp_score = -3
for r in range(x - 1, x + 2):
for c in range(y - 1, y + 2):
if (r == x and c == y) or not is_valid_coordinate(r, c):
continue
if virtual_env[r][c] == 'P':
tmp_score += 1
return tmp_score
danger_point = 0
while hq:
_, now_x, now_y = heapq.heappop(hq)
if virtual_env[now_x][now_y] == 'E':
break
danger_point += calc_point(now_x, now_y)
for direction in range(4):
tmp_x = now_x + dx[direction]
tmp_y = now_y + dy[direction]
if (tmp_x * H + tmp_y) in visited:
continue
if not is_valid_coordinate(tmp_x, tmp_y):
continue
if virtual_env[tmp_x][tmp_y] == 'E':
heapq.heappush(hq, (0, tmp_x, tmp_y))
elif virtual_env[tmp_x][tmp_y] == 'P':
heapq.heappush(hq, (1, tmp_x, tmp_y))
elif virtual_env[tmp_x][tmp_y] == '0':
heapq.heappush(hq, (2, tmp_x, tmp_y))
visited.add(tmp_x * H + tmp_y)
print(danger_point)
Review
- 역시 대회용 알고리즘도 기본적인 코딩테스트에 나오는 문제들을 포함하고는 있지만, 케이스가 아주 다양한 것 같다.
- 게다가 처음 들어보는
KMP
, MCMF
알고리즘이나, Trie
자료구조를 보고 리뷰는 멈추기로 했다.
- 설명을 보니, 문자열을 빠르게 찾는 알고리즘이
KMP
나, Trie
자료구조를 활용하는 방법이라고 한다.
MCMF
알고리즘은 최소 비용 최대 유량 알고리즘으로 최소 비용은 최단 거리 알고리즘인 Dijkstra
또는 벨만포드
알고리즘을 사용하며, 각 상황에서의 최대 유량을 구해주면 된다고 하는데 잘 모르겠다.
- 아직까지는 그저.. 코딩테스트를 푸는 정도의 수준으로만 가능할 것 같다.
- 추후에 시간이 된다면,
종만북
을 보고, 대회용 알고리즘도 리뷰할 수 있도록 하겠습니다… 나약한 저는 이만…