seukseok의 개인 블로그

BOJ 풀이 노트: 피보나치 DP와 다익스트라 최단경로 점검

· tech

BOJ 1003, 1753 풀이를 중심으로 호출 횟수 DP와 우선순위 큐 기반 최단경로 구현의 실전 포인트를 정리했다.

오늘은 성격이 다른 두 문제를 묶어서 풀었다.

1003은 재귀 호출 패턴을 DP로 치환하는 문제이고, 1753은 가중치가 있는 단일 시작점 최단거리 문제의 기본형이다.

1) BOJ 1003 - 피보나치 함수

문제 핵심 요약

피보나치 재귀 함수를 호출했을 때 fibonacci(0)fibonacci(1)이 각각 몇 번 호출되는지 구하는 문제다.

접근 아이디어(왜 이 방법인지)

직접 재귀를 돌리면 중복 호출이 매우 많아진다. 호출 횟수 자체도 피보나치 점화식을 따르기 때문에 DP 테이블로 한 번만 계산해두면 된다.

dp[n] = {zeroCount, oneCount}로 두고,

로 채우면 각 질의를 O(1)에 답할 수 있다.

시간/공간 복잡도

실수하기 쉬운 포인트

C++ 코드 설명(핵심 라인)

dp[0] = {1, 0};
dp[1] = {0, 1};
for (int i = 2; i <= 40; i++) {
    dp[i].first = dp[i - 1].first + dp[i - 2].first;
    dp[i].second = dp[i - 1].second + dp[i - 2].second;
}

호출 횟수 쌍을 점화식으로 누적하는 핵심 구간이다.

cout << dp[n].first << ' ' << dp[n].second << '\n';

전처리된 값을 바로 출력해 각 테스트케이스를 상수 시간에 처리한다.

다른 풀이 가능성


2) BOJ 1753 - 최단경로

문제 핵심 요약

방향 그래프에서 시작 정점 K로부터 모든 정점까지의 최단거리를 구하는 문제다. 도달할 수 없는 정점은 INF를 출력한다.

접근 아이디어(왜 이 방법인지)

간선 가중치가 양수이므로 다익스트라 알고리즘이 정석이다. 우선순위 큐에 (현재까지 거리, 정점)을 넣고 가장 짧은 후보부터 확정해 나가면 된다.

핵심은 이미 더 짧은 거리로 갱신된 항목은 버리는 것이다.

시간/공간 복잡도

실수하기 쉬운 포인트

C++ 코드 설명(핵심 라인)

priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
dist[K] = 0;
pq.push({0, K});

최소 힙으로 사용할 우선순위 큐를 만들고 시작점을 초기화한다.

if (curDist > dist[curNode]) continue;
for (auto [nextNode, weight] : graph[curNode]) {
    int nextDist = curDist + weight;
    if (nextDist < dist[nextNode]) {
        dist[nextNode] = nextDist;
        pq.push({nextDist, nextNode});
    }
}

느슨한(오래된) 큐 항목을 건너뛰고, 더 짧은 경로가 발견될 때만 갱신하는 전형적인 다익스트라 패턴이다.

다른 풀이 가능성


오늘 포인트는 두 가지다.

서로 다른 유형을 하루에 2문제씩 고정 루틴으로 섞어 풀면, 자료구조 선택 감각과 구현 정확도가 같이 올라간다.