카테고리: boj
"boj" 로 분류된 글.
학생은 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 로 접근했다.
첫째 줄에 도시의 개수 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 로 접근했다.
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 로 접근했다.
- 각 컴퓨터마다 BFS: O(N + M)
- 전체 N개 컴퓨터: O(N × (N + M))
- N ≤ 10,000, M ≤ 100,000
- 최악의 경우: 10,000 × 110,000 = 1,100,000,000
시간 제한이 5초이고, 파이썬은 초당 약 1억 번 연산이 가능하므로 통과 가능하다.
시간이 빡빡할 경우 다음 최적화를 고려할 수 있다:
-
빠른 입출력:
sys.stdin.readline()사용 -
DFS 대신 BFS: 재귀 오버헤드 감소
-
조기 종료: 이미 방문한 노드 재탐색 방지
-
역방향 그래프: A→B가 아닌 B→A로 저장
-
자기 자신 포함: 해킹한 컴퓨터 자신도 카운트에 포함
-
오름차순 출력: 여러 개일 경우 정렬 필요
-
빠른 입출력: N, M이 크므로 필수
이 문제는 “신뢰 관계”를 반대로 생각해야 한다:
- “A가 B를 신뢰” ≠ A를 해킹하면 B도 해킹됨 (X)
- “A가 B를 신뢰” = B를 해킹하면 A도 해킹됨 (O)
효율적인 해킹
백준 1325번 '효율적인 해킹' (실버 1) 문제 풀이. graph theory, graph traversal, bfs 로 접근했다.
def find(parent, x):
if parent[x] != x:
parent[x] = find(parent, parent[x])
return parent[x]
def union(parent, a, b):
a = find(parent, a)
b = find(parent, b)
if a < b:
parent[b] = a
else:
parent[a] = b
N, M = map(int, input().split())
truth = list(map(int, input().split()))
truth_num = truth[0]
truth_people = set(truth[1:])
parent = list(range(N + 1))
parties = []
for _ in range(M):
party = list(map(int, input().split()))
party_people = party[1:]
parties.append(party_people)
# 같은 파티 사람들을 union
for i in range(len(party_people) - 1):
union(parent, party_people[i], party_people[i + 1])
# 진실을 아는 사람들과 같은 그룹인지 확인
result = 0
for party in parties:
can_lie = True
for person in party:
for truth_person in truth_people:
if find(parent, person) == find(parent, truth_person):
can_lie = False
break
if not can_lie:
break
if can_lie:
result += 1
print(result)거짓말
백준 1043번 '거짓말' (골드 4) 문제 풀이. graph theory, data structures, graph traversal 로 접근했다.
import re
N = int(input())
room = [input() for _ in range(N)]
# 가로
row_cnt = sum(len(re.findall(r'\.{2,}', row)) for row in room)
# 세로
transposed = [''.join(row[i] for row in room) for i in range(N)]
col_cnt = sum(len(re.findall(r'\.{2,}', col)) for col in transposed)
print(row_cnt, col_cnt)
정규표현식 \.{2,}는 “연속된 2개 이상의 .”을 의미한다.
누울 자리를 찾아라
백준 1652번 '누울 자리를 찾아라' (실버 5) 문제 풀이. implementation, string 로 접근했다.
N, K = map(int, input().split())
distance = [float('inf')] * 100001
def bfs_01(start):
dq = deque([(0, start)])
distance[start] = 0
while dq:
dist, c = dq.popleft()
if distance[c] < dist:
continue
# 비용 0인 간선 (순간이동)
n = c * 2
if 0 <= n <= 100000 and dist < distance[n]:
distance[n] = dist
dq.appendleft((dist, n)) # 앞에 추가
# 비용 1인 간선 (걷기)
for n in (c + 1, c - 1):
if 0 <= n <= 100000 and dist + 1 < distance[n]:
distance[n] = dist + 1
dq.append((dist + 1, n)) # 뒤에 추가
bfs_01(N)
print(distance[K])숨바꼭질 3
백준 13549번 '숨바꼭질 3' (골드 5) 문제 풀이. graph theory, graph traversal, bfs 로 접근했다.