Search

[백준] ACM Craft

문제 개요

오늘의 코딩 테스트 문제는 백준의 ACM Craft였다. 게임 개발 시뮬레이션 문제로, 건물 건설 순서와 시간을 고려해 최적의 건설 시간을 계산하는 문제다.

문제 분석

문제의 핵심은 다음과 같다:
1.
건물마다 건설에 필요한 선행 건물이 있다.
2.
여러 건물을 동시에 건설할 수 있다.
3.
특정 건물을 짓는 데 걸리는 최소 시간을 계산해야 한다.
처음엔 단순하게 접근했다가 시간 초과로 실패했다. 문제를 다시 읽어보니 동적 계획법(DP)을 사용해야 한다는 걸 깨달았다.

접근 방식

1.
각 건물별로 선행 건물 목록을 저장한다.
2.
재귀적으로 선행 건물들의 건설 시간을 계산한다.
3.
현재 건물의 건설 시간 + 선행 건물 중 가장 오래 걸리는 시간을 합산한다.

코드 구현

#include <iostream> #include <vector> using namespace std; vector<int> D; vector<int> dp; vector<vector<int>> requires; int getDP(int n) { int max_time = 0; for (int node: requires[n]) { if (dp[node]<0) { getDP(node); } max_time = max(max_time, dp[node]); } dp[n] = D[n] + max_time; return dp[n]; } int main() { int T, N, K; cin >> T; vector<int> results(T); for (int t = 0; t < T; t++) { cin >> N >> K; D.clear(); for (int i = 0; i < N; i++) { int temp; cin >> temp; D.push_back(temp); } vector<pair<int, int>> edges(K); for (int i = 0; i < K; i++) cin >> edges[i].first >> edges[i].second; int W; cin >> W; requires.clear(); for (int i = 0; i < N; i++) { vector<int> require; for (int j = 0; j < K; j++) if (edges[j].second == i+1) require.push_back(edges[j].first-1); requires.push_back(require); } dp.clear(); for (int i=0; i<N; i++) dp.push_back(-1); results[t] = getDP(W-1); } for (int result : results) cout << result << endl; return 0; }
C++
복사
주요 로직은 getDP 함수에 있다. 이 함수는 재귀적으로 각 건물의 최소 건설 시간을 계산한다. 메모이제이션을 사용해 중복 계산을 방지했다.

문제 해결 과정

처음에는 벡터만 사용해서 구현했다가 시간 초과가 발생했다. DP를 적용하고 나서야 해결할 수 있었다. 역방향 의존성(즉, 어떤 건물이 현재 건물의 선행 건물인지)을 처리하는 것도 까다로웠다. 결국 재귀 함수로 이 문제를 해결했다.

회고

1.
DP 문제임을 빨리 캐치하지 못한 게 아쉽다. 문제 유형을 좀 더 빨리 파악할 수 있도록 연습해야겠다.
2.
코드의 가독성과 효율성 사이의 균형을 잡는 게 여전히 어렵다. 헤매면서 수정하다보니 너무 지저분하게 작성했다.
이번 문제를 통해 DP의 중요성을 다시 한번 느꼈다. 알고리즘의 선택이 성능에 얼마나 큰 영향을 미치는지 직접 경험할 수 있었다. 앞으로도 꾸준히 알고리즘 문제를 풀면서 실력을 키워나가야겠다.