프로젝트 간 선행 관계가 주어진 DAG에서, 모든 다른 정점과 반드시 선행 관계(앞서거나 뒤서거나)가 성립하는 “critical” 정점을 찾는 문제이다. 각 정점이 critical인지 판정하려면 해당 정점에서 도달 가능한 정점들과 해당 정점으로 도달 가능한 정점들의 합이 전체 정점 수와 같은지 확인하면 된다. 이를 위해 위상 정렬과 도달 가능성 분석을 활용하여 효율적으로 해결할 수 있다.
문제: https://www.acmicpc.net/problem/12823
문제 요약
N개의 하위 프로젝트(정점)와 선행 관계(유향 간선)가 주어진 DAG에서, 정점 u가 다른 모든 정점 v에 대해 u → v 또는 v → u 중 하나가 반드시 성립하는 정점들을 모두 구한다. 이러한 정점을 문제에서는 “critical”이라 부른다.
정의
- 직접 선행:
u → v는 하위 프로젝트u가v보다 먼저 완료되어야 함을 의미한다. - 선행: 직접 선행의 추이적 개념으로, 어떤
z가 있어u → z이며z → v이면u → v라고 본다. - critical 정점: 모든 다른 정점
v에 대해v → u또는u → v중 하나가 성립하는 정점u. - 사이클 없음: 자기 자신으로 돌아오는 경로가 없어 전체 프로젝트를 완료할 수 있음(즉, 그래프는 DAG).
- 직접 선행:
입력 형식
- 첫 줄:
N M—1 ≤ N ≤ 100000,0 ≤ M ≤ 1000000 - 다음
M줄:u v—1 ≤ u ≠ v ≤ N, 여기서u는v의 직접 선행 관계를 의미
- 첫 줄:
출력 형식
- 첫 줄: critical 정점의 개수
K - 둘째 줄: critical 정점의 번호를 오름차순으로 공백으로 구분해 출력
- critical 정점이 하나도 없으면 첫 줄에
0만 출력
- 첫 줄: critical 정점의 개수
제한
- 시간 제한: 0.6초
- 메모리 제한: 32 MB
예제
입력
1 2 3 4 5 6 7 8 9 107 9 1 3 2 3 3 4 3 5 4 6 5 6 1 7 3 7 7 4출력
1 22 3 6
참고: 원문은 BOJ 12823 — Critical Projects.
핵심 아이디어
- DAG의 위상 순서를
p[1..N]라 하자.p[k]가 critical이려면:- 앞쪽 부분 그래프
[1..k]에서p[k]가 유일한 싱크여야 한다. - 뒤쪽 부분 그래프
[k..N]에서p[k]가 유일한 소스여야 한다.
- 앞쪽 부분 그래프
- 이를 O(N+M)으로 판정할 수 있다.
pos[u]: 위상 순서에서 u의 위치minOutIdx[u]: 간선u→v에 대해min(pos[v])(없으면N+1)maxInIdx[v]: 간선u→v에 대해max(pos[u])(없으면0)- k에서 프리픽스 싱크 수 =
pos[i] ≤ k이면서minOutIdx[i] > k인 i의 개수- 각 i는 구간
k ∈ [pos[i], minOutIdx[i]-1]에서 싱크에 기여 → 차분 배열로 일괄 집계
- 각 i는 구간
- k에서 서픽스 소스 수 =
pos[j] ≥ k이면서maxInIdx[j] < k인 j의 개수- 각 j는 구간
k ∈ [maxInIdx[j]+1, pos[j]]에서 소스에 기여 → 차분 배열로 일괄 집계
- 각 j는 구간
- 두 값이 모두 1인 k의 정점만 critical.
메모리 제약(32MB)과 M ≤ 1e6을 고려하여, forward-star 인접 리스트와 빠른 입력, O(N+M) 알고리즘으로 구현한다.
C++17 풀이
| |
복잡도
- 시간: O(N + M)
- 공간: O(N + M) — 인접 리스트(Forward-star), 각종 보조 배열
포인트 정리
- 위상 정렬 한 번과 간선 한 번의 순회로
minOutIdx,maxInIdx산출 - 프리픽스 싱크/서픽스 소스의 “유일성”을 차분 배열 누적으로 O(N)에 판정
- 대규모 입력(최대 1e6 간선) 대비 빠른 입력과 저메모리 구현
코너 케이스 및 실수 포인트
| 케이스 | 설명 | 처리 방법 |
|---|---|---|
| 최소 입력 | N=1 또는 빈 입력 | 반복문 범위·예외 처리 확인 |
| 오버플로우 | 답이 $2^{31}$ 초과 가능 | long long (C++) 등 사용 |
![Featured image of post [Algorithm] C++ 백준 12823번 : Critical Projects](/post/algorithm/2025-08-08-boj-12823/wordcloud_hu_9eae430c48f4a764.webp)
![[Algorithm] C++ 백준 9208번 : Ringworld](/post/algorithm/2025-08-12-boj-9208-ringworld-cpp-solution/wordcloud_hu_4354cf7ff06c767f.webp)
![[Algorithm] C++ 백준 1150번 : 백업](/post/algorithm/2025-08-08-boj-1150/wordcloud_hu_33a41263223fb38f.webp)
![[Algorithm] C++ 백준 12823번 : Critical Projects](/post/algorithm/2025-08-08-boj-12823/wordcloud_hu_e7fcbc9c24975c1d.webp)
![[Algorithm] C++ 백준 1605번: 반복 부분문자열](/post/algorithm/2025-08-08-boj-1605/wordcloud_hu_9f6672f2dc85b0d5.webp)
![[Algorithm] C++ 백준 3654번 : L퍼즐](/post/algorithm/2025-08-08-boj-3654/wordcloud_hu_7023f42797db5ede.webp)
![[Algorithm] C++ 백준 13361번 : 최고인 대장장이 토르비욘](/post/algorithm/2025-02-10-boj-13361/index_hu_8aea481bdf7da831.webp)
![[Algorithm] C++/Python 백준 5542번 : JOI 국가의 행사](/post/algorithm/2024-12-26-boj-5542/wordcloud_hu_4a8e4147d94919b3.webp)
![[Algorithm] C++ 백준 16746번: Four-Coloring](/post/algorithm/2025-12-04-boj-16746-four-coloring-cpp-solution/wordcloud_hu_105ddab302f06a2d.webp)
![[Algorithm] C++ 백준 7577번: 탐사](/post/algorithm/2025-12-02-boj-7577-exploration-difference-constraints-spfa-cpp-solution/wordcloud_hu_77e00c99bfe3b1d9.webp)
![[Algorithm] C++/Python 백준 18251번 내 생각에 A번인 DFS 문제가 E번이 된 사연 (Easy)](/post/algorithm/2025-02-08-boj-18251/index_hu_48488348507365c9.webp)