Posts
All the articles I've posted.
학생은 1번부터 N²번까지 번호가 매겨져 있고, (r, c)는 r행 c열을 의미한다. (r, c)의 인접한 칸은 (r-1, c), (r+1, c), (r, c-1), (r, c+1)이다.
학생이 좋아하는 학생 4명이 주어지고, 다음 순서로 자리를 배정한다.
- 비어있는 칸 중에서 좋아하는 학생이 인접한 칸에 가장 많은 칸으로 자리를 정한다.
- 1을 만족하는 칸이 여러 개이면, 인접한 칸 중에서 비어있는 칸이 가장 많은 칸으로 자리를 정한다.
- 2를 만족하는 칸도 여러 개인 경우에는 행의 번호가 가장 작은 칸으로, 그러한 칸도 여러 개이면 열의 번호가 가장 작은 칸으로 자리를 정한다.
학생의 만족도는 자리 배치가 모두 끝난 후에 구할 수 있다. 학생의 만족도를 구하려면 그 학생과 인접한 칸에 앉은 좋아하는 학생의 수를 구해야 한다. 그 값이 0이면 0, 1이면 1, 2이면 10, 3이면 100, 4이면 1000이다.
구현 문제이다. 주어진 규칙대로 정확하게 구현하면 된다.
상어 초등학교
백준 21608번 '상어 초등학교' (골드 5) 문제 풀이. implementation 로 접근했다.
SELECT e1.id
FROM ecoli_data AS e1
JOIN ecoli_data AS e2 ON e1.parent_id = e2.id
JOIN ecoli_data AS e3 ON e2.parent_id = e3.id
WHERE e3.parent_id IS NULL
ORDER BY e1.id ASC
문제에서 요구한 결과를 만들기 위해 쿼리에서 실제로 쓴 것들이다.
- 테이블 2회 JOIN 으로 두 테이블을 연결
- WHERE 로 조건에 맞는 행만 남김
- ORDER BY 로 정렬
특정 세대의 대장균 찾기
ecoli_data 를 세 번 조인해 부모의 부모까지 거슬러 올라가고, 그 위가 NULL 인 경우만 남겨 3세대를 찾는다.
WITH per AS (
SELECT id, PERCENT_RANK() OVER (ORDER BY size_of_colony DESC) as per_rank
FROM ECOLI_DATA
)
SELECT id,
CASE
WHEN per_rank < 0.25 THEN 'CRITICAL'
WHEN per_rank < 0.5 THEN 'HIGH'
WHEN per_rank < 0.75 THEN 'MEDIUM'
ELSE 'LOW'
END AS colony_name
FROM per
ORDER BY id;
문제에서 요구한 결과를 만들기 위해 쿼리에서 실제로 쓴 것들이다.
- ORDER BY 로 정렬 (내림차순 포함)
- 서브쿼리를 사용
- CASE WHEN 으로 조건에 따라 값을 분기
대장균의 크기에 따라 분류하기 2
PERCENT_RANK() 윈도 함수로 크기 백분위를 매기고, CASE 로 25%·50%·75% 구간을 잘라 등급 이름을 붙인다.
첫째 줄에 도시의 개수 N, 도로의 개수 M, 거리 정보 K, 출발 도시의 번호 X가 주어진다. (2 ≤ N ≤ 300,000, 1 ≤ M ≤ 1,000,000, 1 ≤ K ≤ 300,000, 1 ≤ X ≤ N)
둘째 줄부터 M개의 줄에 걸쳐서 두 개의 자연수 A, B가 공백을 기준으로 구분되어 주어진다. 이는 A번 도시에서 B번 도시로 이동하는 단방향 도로가 존재한다는 의미다. (1 ≤ A, B ≤ N)
출력
X로부터 출발하여 도달할 수 있는 도시 중에서, 최단 거리가 K인 모든 도시의 번호를 한 줄에 하나씩 오름차순으로 출력한다.
이 때 도달할 수 있는 도시 중에서, 최단 거리가 K인 도시가 하나도 존재하지 않으면 -1을 출력한다.
단방향 그래프에서 특정 노드로부터의 최단 거리를 구하는 문제이다. 모든 간선의 가중치가 1이므로 BFS 또는 다익스트라로 해결할 수 있다.
import heapq
from collections import defaultdict
INF = float("inf")
N, M, K, X = map(int, input().split())
graph = defaultdict(list)
for _ in range(M):
a, b = map(int, input().split())
graph[a].append(b)
def dijkstra(start):
dist_list = [INF] * (N + 1)
dist_list[start] = 0
q = [(0, start)]
while q:
dist, cur_node = heapq.heappop(q)
if dist_list[cur_node] < dist:
continue
for n_node in graph[cur_node]:
if dist + 1 < dist_list[n_node]:
dist_list[n_node] = dist + 1
heapq.heappush(q, (dist + 1, n_node))
return dist_list
inf_cnt = 0
for node, dist in enumerate(dijkstra(X)[1:], start=1):
if dist == K:
print(node)
else:
inf_cnt += 1
if inf_cnt == N:
print(-1)특정 거리의 도시 찾기
백준 18352번 '특정 거리의 도시 찾기' (실버 2) 문제 풀이. graph theory, graph traversal, bfs 로 접근했다.
N, C = map(int, input().split())
houses = sorted([int(input()) for _ in range(N)])
# 집 사이 최소 거리
start = 1
# 집 사이 최대 거리
end = houses[-1] - houses[0]
result = 0
# C개의 공유기를 모두 설치할 수 있는 mid를 찾기기
while start <= end:
mid = (start + end) // 2
count = 1
cur_house = houses[0]
for i in range(1, N):
# 현재 집과의 거리가 mid보다 크거나 같을 때 -> 설치 가능
if houses[i] - cur_house >= mid:
count += 1
cur_house = houses[i]
# 가능한 경우 더 큰 mid를 탐색
if count >= C:
result = mid
start = mid + 1
else:
end = mid - 1
print(result)공유기 설치
백준 2110번 '공유기 설치' (골드 4) 문제 풀이. binary search, parametric search 로 접근했다.
WITH null_item as (SELECT t1.item_id
FROM item_tree as t1
LEFT JOIN
item_tree as t2
ON t1.item_id = t2.parent_item_id
WHERE t2.item_id IS NULL
)
SELECT ii.item_id, ii.item_name, ii.rarity
FROM null_item as ni
JOIN
item_info as ii
ON ni.item_id = ii.item_id
ORDER BY ii.item_id DESC
문제에서 요구한 결과를 만들기 위해 쿼리에서 실제로 쓴 것들이다.
- 테이블 2회 LEFT JOIN 으로 두 테이블을 연결
- WHERE 로 조건에 맞는 행만 남김
- ORDER BY 로 정렬 (내림차순 포함)
- 서브쿼리를 사용
업그레이드 할 수 없는 아이템 구하기
item_tree 를 자기 자신과 LEFT JOIN 해서 자식이 없는(NULL 인) 아이템만 남긴다 — 더 업그레이드할 수 없는 아이템이다.
SELECT car_type, COUNT(car_id) as cars
FROM car_rental_company_car
WHERE options REGEXP '통풍시트|열선시트|가죽시트'
GROUP BY car_type
ORDER BY car_type
-- WHERE car.options like '%통풍시트%'
-- OR car.options like '%열선시트%'
-- OR car.options like '%가죽시트%'
문제에서 요구한 결과를 만들기 위해 쿼리에서 실제로 쓴 것들이다.
- WHERE 로 조건에 맞는 행만 남김
- GROUP BY 로 묶어서 집계
- ORDER BY 로 정렬
- 사용한 함수: COUNT()
자동차 종류 별 특정 옵션이 포함된 자동차 수 구하기
LIKE 를 OR 로 세 번 잇는 대신 REGEXP 로 세 옵션을 한 번에 매칭하고 차종별로 COUNT 한다. 원래 쓰던 LIKE 버전도 주석으로 남겨 두었다.
MAX_W = 1000
N, M = map(int, input().split())
if N != 0:
books = list(map(int, input().split()))
cnt = 1
remain_w = M
for book in books:
# 더 넣을 수 없으면 포장
if remain_w < book:
cnt += 1
remain_w = M
remain_w -= book
print(cnt)
else:
print(0)짐 챙기는 숌
백준 1817번 '짐 챙기는 숌' (실버 5) 문제 풀이. implementation, greedy algorithm, simulation 로 접근했다.
첫째 줄에 지도의 세로 크기 N, 가로 크기 M (1 ≤ N, M ≤ 20), 주사위를 놓은 곳의 좌표 x, y(0 ≤ x ≤ N-1, 0 ≤ y ≤ M-1), 그리고 명령의 개수 K (1 ≤ K ≤ 1,000)가 주어진다.
둘째 줄부터 N개의 줄에 지도에 쓰여 있는 수가 북쪽부터 남쪽으로, 각 줄은 서쪽부터 동쪽 순서대로 주어진다. 주사위를 놓은 곳의 수는 항상 0이다. 지도의 각 칸에 쓰여 있는 수는 10 미만의 자연수 또는 0이다.
마지막 줄에는 이동하는 명령이 순서대로 주어진다. 동쪽은 1, 서쪽은 2, 북쪽은 3, 남쪽은 4로 주어진다.
출력
이동할 때마다 주사위의 윗 면에 쓰여 있는 수를 출력한다. 만약 바깥으로 이동시키려고 하는 경우에는 해당 명령을 무시하고, 출력도 하지 않는다.
주사위의 상태를 관리하며 시뮬레이션하는 구현 문제이다.
주사위 굴리기
백준 14499번 '주사위 굴리기' (골드 4) 문제 풀이. implementation, simulation 로 접근했다.