안녕하세요. 이번 강좌에서는 C++ 코딩테스트에서 자주 출제되는 알고리즘 문제 중 하나인 “임계 경로 구하기”에 대해 다루어 보겠습니다. 이 문제는 주로 그래프 이론과 관련된 중요한 개념을 이해하는 데 도움이 됩니다.
문제 정의
주어진 방향 그래프에서 각 정점이 특정 작업을 수행하는 시간을 가지고 있습니다. 임계 경로는 모든 정점을 방문하고, 시작 정점에서 도착 정점으로 가는 경로 중에서 가장 긴 경로의 총 작업 시간을 의미합니다.
문제 설명
그래프의 정점 수 n
과 간선 수 m
이 주어지고, 각 정점 i
에 대해 작업 시간이 t[i]
로 주어집니다. 다음과 같은 조건을 만족하는 경로의 작업 시간의 최대값을 구하는 문제입니다.
입력: n, m t[0], t[1], ..., t[n-1] 간선: (u1, v1), (u2, v2), ..., (um, vm) 출력: 최대 작업 시간
입력 예시
5 6 2 3 1 5 4 0 1 0 2 1 3 2 3 2 4 3 4
출력 예시
10
문제 해결 전략
1. 그래프 표현
우리는 먼저 주어진 정보에 따라 그래프를 인접 리스트 형태로 구성합니다. 이를 통해 각 정점에서 연결된 정점으로의 이동을 쉽게 관리할 수 있습니다.
2. 최장 경로 찾기
DFS(Depth-First Search) 또는 DAG(Directed Acyclic Graph) 성질을 이용해 최장 경로를 구할 수 있습니다. 각 정점을 방문하면서 최장 경로의 최대 작업 시간을 저장해 나가는 방식으로 진행합니다.
3. 동적 프로그래밍(DP) 활용
특히, 임계 경로 구하기 문제는 동적 프로그래밍을 통해 효율적으로 해결할 수 있습니다. 각 정점을 기준으로 도달 가능한 모든 경로의 최대를 누적하여 기록합니다.
C++ 코드 구현
#include#include #include using namespace std; vector timeTaken; // 각 정점의 작업 시간 vector > graph; // 그래프 인접 리스트 vector dp; // DP 배열 int dfs(int node) { if (dp[node] != -1) return dp[node]; int maxTime = 0; for (int next : graph[node]) { maxTime = max(maxTime, dfs(next)); } dp[node] = maxTime + timeTaken[node]; return dp[node]; } int main() { int n, m; cin >> n >> m; timeTaken.resize(n); graph.resize(n); dp.assign(n, -1); for (int i = 0; i < n; i++) { cin >> timeTaken[i]; } for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); } int result = 0; for (int i = 0; i < n; i++) { result = max(result, dfs(i)); } cout << result << endl; return 0; }
코드 설명
위 코드는 그래프를 DFS 형태로 탐색하여 임계 경로의 최대 작업 시간을 계산하는 방식입니다. 주요 요소는 다음과 같습니다:
- 그래프 생성: 입력받은 간선을 통해 인접 리스트 형태로 그래프를 구성합니다.
- DFS 함수: 각 정점을 시작으로 연결된 정점들을 재귀적으로 탐색하며 최장 경로의 시간을 계산합니다.
- DP 배열: 동일한 정점을 여러 번 방문하지 않도록 DP 배열을 활용하여 메모이제이션 기법을 사용합니다.
시간 복잡도
이 알고리즘의 시간 복잡도는 O(n + m)입니다. n은 정점의 수, m은 간선의 수입니다. 최악의 경우 모든 정점을 한 번씩 방문해야 하므로, 이 정도의 복잡도는 일반적으로 효율적입니다.
결론
이번 강좌에서는 C++를 사용하여 임계 경로 구하기 문제를 해결하는 방법에 대해 학습하였습니다. 그래프 이론, 동적 프로그래밍 및 DFS의 개념을 통해 이러한 유형의 문제를 해결할 수 있습니다. 앞으로도 다양한 알고리즘 문제를 연습하여 더 나은 프로그래밍 실력을 갖추시길 바랍니다.