2025년도 정보올림피아드 2차대회

2025년 KOI 2차대회 

2025년도 한국정보올림피아드 2차대회 문제풀이 입니다.

갈수록 제 머리가 나빠지는 것인지 아니면 대회 문제가 점점 어려워지는 것인지, 쉽지 않습니다. 

제 주관적인 관점에서 볼 때, 대회 초, 중등부 난이도는 대학 전공자 3학년 이상 수준이며, 고등부는 기업입사 면접문제보다 어렵다고 생각합니다. 

그래도 해야지 답이 없습니다. 😅

[해인사에서 만난 무서운 비석]
 

시간나는대로 풀고 업데이트하겠으며, 오답, 만점이 아닌 경우도 존재합니다.

 

초등부 장애물 

문제링크 

첫 문제라 쉽습니다. 장애물 개수만큼 반복하며 장애물위치-내위치를 비교해 가며 이동하면 풀 수 있습니다.

N = int(input())
X = list(map(int, input().split(' ')))

s = 0
e = X[-1]+1
i = 0
cnt = 0

while i<N:
    if X[i] > s:
        if X[i]-s==1:
            s+=2
            i+=1                                    
        elif X[i]-s==2:
            s+=1            
        elif X[i]-s>2:
            s = s+2
        cnt += 1        
    else:
        cnt = -1
        break    

print(cnt)

 

초등부 거울 

문제링크

저는 첫문제보다 어려웠는데 정답률은 더 높네요.  

거울의 위치는 정렬되어 있으며 a, b의 값이 작은수, 큰수 or 큰수, 작은수 중 어떻게 적용되어야 커지는지 확인이 필요합니다.

N, a = map(int, input().split(' '))
b = list(map(int, input().split(' ')))

k = a
mid = N//2
na = N%2

if na==0:
    # 짝수의 경우 반씩 나눠 좌, 우시작점에서 인덱스 증가
    for i in range(mid):
        k = 2*b[i]-k
        k = 2*b[i+mid]-k
else:
    # 홀수의 경우 반대 순서, 마지막 중간값처리
    for i in range(mid):
        k = 2*b[N-i-1]-k
        k = 2*b[i]-k

    k = 2*b[mid]-k

print(k)

 

초등부 통행료

문제링크

처음에는 다익스트라와 헷깔렸습니다. 플로이드 워셜 알고리즘을 공부해보세요.

import sys
INF = float('inf')

# 입력처리
N,M = map(int, sys.stdin.readline().split(' '))
W = []
for i in range(M):
    u, v = map(int, sys.stdin.readline().split(' '))
    W.append((u-1,v-1))

dist = [[INF] * N for _ in range(N)]

for i in range(N):
    dist[i][i] = 0

# 처음부터 연결도로 비용 1로 설정
for u,v in W:
    dist[u][v] = 1
    dist[v][u] = 1
   
# 전체 플로이드 워셜(모든 도로 비용 1기준)
for k in range(N):
    for i in range(N):
        for j in range(N):
            # i, j 경로에 대해 i -> k -> j, 즉 k를 거치는게 더 짧은지 확인
            dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])

last_total = 0
for i in range(N):
    for j in range(N):
        last_total += dist[i][j]
#print(last_total, end='\n')    

# 역으로 도로비용을 0으로 하나씩 변경
rdist = [0] * M
rdist[M-1] = last_total

for day in range(M-1, 0, -1):
    u, v = W[day] 

    # 새로 0원이된 도로적용
    for i in range(N):
        for j in range(N):
            new_dist = min(dist[i][u] + dist[v][j]  , dist[i][v] + dist[u][j])
            dist[i][j] = min (dist[i][j], new_dist)        

    # 총합 계산
    total = 0
    for i in range(N):
        for j in range(N):
            total += dist[i][j]
    rdist[day-1] = total

for r in rdist:
    #print(r, end='\n')   
    sys.stdout.write(f'{r}\n')

 

초등부 상자보관

문제링크 

큰상자안에 작은상자를 넣어 상자그룹을 생성한 후, 최대상자크기, 용량 그리고 최소상자 크기, 용량을 저장하는 방식으로 하다 마지막 예시에서 실패하였습니다.

생각해보니 단순 크기 비교만 할 것이 아니라 효율적인 상자배치가 요구되므로 순열을 통한 전체탐색으로 시도중입니다.

from itertools import permutations

N = int(input())
boxes = []
for i in range(N):
    s, c = map(int, input().split(' ')) 
    boxes.append((s,c))

def isInBox(a, b):
    sa, ca = a
    sb, cb = b
    return sb <= ca

for i in range(1, N+1):
    subbox = boxes[:i]
    n = len(subbox)
    # 최대 모든 박스가 개별그룹
    cnt = n

    # 상자 간 포함 관계를 전체 탐색 (모든 순열)
    for p in permutations(range(n)):
        # 다른상자에 들어갔는지
        isin = [False] * n
        for j in range(n):
            for k in range(j + 1, n):
                outer = subbox[p[j]]
                inner = subbox[p[k]]
                if not isin[p[k]] and isInBox(outer, inner):
                    isin[p[k]] = True
                    break
        subcnt = isin.count(False)
        cnt = min(cnt, subcnt)
    print(cnt)

 

중등부 가방

문제링크 

물건의 무게가 입력시 정렬되어 있는줄 착오가 있었습니다. 무게별로 정렬하고, 미리 물건 누적합을 구해둡니다. 정렬되어 있다면, 주인이 가져간 물건 다음 물건부터 도둑이 가져갈 물건입니다.

#N:상점물건수, K:도둑훔겨갈갯수 C:주인가방최대무게
import sys

N, K, C = map(int, input().split(' '))
A = list(map(int, input().split(' ')))
A.sort()

# 누적합
pre = [0] * (N + 1)
for i in range(1, N + 1):
    pre[i] = pre[i - 1] + A[i - 1]

for i in range(1, C + 1):    
    D = 0

    for j in range(N + 1):
        # 주인이 가져간 무게합                
        W = pre[j]

        if W > i:
            break

        # 도둑에게 남은 물건
        R = N - j
        S = min(R, K)
        
        P = 0
        if S > 0:
            # 남은 물건: A[j]부터 시작
            # 도둑이 훔치는 물건: A[j]부터 Aj + S - 1]까지
            P = pre[j+S] - pre[j]            
        
        # 4. 최대 피해 갱신
        D = max(D, P)
        
    sys.stdout.write(f'{D}\n')

 

중등부 로봇

문제링크

점프대 위치를 집합으로 저장해 이진탐색을 활용, 점프 파워는 딕셔너리로 저장해 시도중입니다.

import sys

n = int(sys.stdin.readline())
jpos = set()
jpow = dict()
for i in range(n):
    # x:점프대위치, p:초기점프파워, 점프후 2배증가
    x, p = map(int, sys.stdin.readline().split(' '))
    jpos.add(x)
    jpow[x] = p

q = int(sys.stdin.readline())
for i in range(q):
    # s에서 출발, t시간이 지난후 도달위치
    s, t = map(int, sys.stdin.readline().split(' '))
    jpow_copy = dict(jpow)

    while t>0:
        if s in jpos:
            bs = s
            s = s+jpow_copy[s]
            jpow_copy[bs] = jpow_copy[bs]*2
        else:
            s-=1

        t-=1
    #print(s)
    sys.stdout.write(f'{s}\n')

 

고등부 문제도 시간나는 대로 업데이트 하겠습니다. 

감사합니다. 

댓글

이 블로그의 인기 게시물

Qt Designer 설치하기

파이썬을 활용한 PID 제어기 GUI 구현

PyQt5 기반 동영상 플레이어앱 만들기