문제: BOJ 2988 - 아보가드로
이 문제는 3×N 표에서 일부 열을 지운 뒤 각 행을 오름차순 정렬했을 때, 정렬된 표의 모든 열에서 값이 같아지게 만드는 “열 선택” 문제다.
첫 행이 1..N 순열이라는 점을 이용하면, 각 값 \(x\)가 선택될 때 2행/3행이 만들어내는 값이 각각 하나로 정해져 함수 그래프(Functional Graph) 2개로 환원된다.
문제 정보
문제 요약:
- 길이 \(N\)인 3행 표가 있다.
- 1행은 1..N이 중복 없이 한 번씩(순열) 등장한다.
- 2행/3행은 1..N 범위의 수가 임의로 주어진다(중복 가능).
- 일부 열을 삭제한 뒤, 각 행을 오름차순 정렬했을 때 정렬된 표에서 같은 열의 값(3행)이 모두 일치하게 하고 싶다.
- 삭제해야 하는 열의 최소 개수를 구한다.
제한 조건:
- 시간 제한: 1초
- 메모리 제한: 128MB
- \(1 \le N \le 100{,}000\)
입출력 예제
예제 입력 1:
| |
예제 출력 1:
| |
예제 입력 2:
| |
예제 출력 2:
| |
아이디어 요약
- 열 \(i\)를 남기면 (정렬 이전 기준) 1행 값 \(A_i\)가 “선택된 값”에 포함된다.
- 1행은 순열이므로 값 \(x\)는 정확히 한 열에서만 등장한다. 따라서 “값 관점”으로 보면:
- \(x\)를 남긴다면, 그 열에서 2행 값이 어떤 \(f(x)\)로, 3행 값이 어떤 \(g(x)\)로 결정된다.
- 즉 \(f, g : \{1..N\} \to \{1..N\}\) 인 함수 2개가 생긴다.
- 정렬 후 세 행이 열별로 같아지려면, 남긴 값들의 집합(1행)은 어떤 집합 \(S\)이고,
- 2행의 값 다중집합도 \(S\),
- 3행의 값 다중집합도 \(S\) 이어야 한다.
- 함수 그래프에서 “\(S\)를 골랐을 때 \(f(S)=S\)이고 중복이 없어야 함”은 결국 사이클(순환)만 통째로 선택하는 것과 동치다.
- 따라서 답은 “\(f\)와 \(g\) 둘 다에서 사이클에 속하며, 각 사이클을 부분적으로 선택할 수 없다는 제약을 동시에 만족하는 최대 크기 \(S\)”를 찾아 \(N-|S|\)를 출력하면 된다.
접근 방식
1) 값→값 함수 만들기
입력에서 1행이 순열이므로 값 \(x\)의 위치를 \(pos[x]\)라고 두면,
- \(f(x) = B_{pos[x]}\)
- \(g(x) = C_{pos[x]}\)
이제 “값 1..N”은 정점이 되고, 간선 \(x \to f(x)\), \(x \to g(x)\) 를 갖는 함수 그래프 2개를 다룬다.
2) 각 함수 그래프의 ‘사이클 정점’만 남기기
함수 그래프에서 사이클이 아닌 정점(나무 부분)은 위상 제거(진입차수 0부터 큐로 제거)로 찾을 수 있다.
- 사이클에 속한 정점만
inCycleF[x],inCycleG[x]로 표시한다.
3) “사이클은 통째로” 제약을 만족하는 최대 집합 찾기 (폐포)
먼저 둘 다 사이클인 정점만 후보로 둔다:
\[ alive[x] = inCycleF[x] \land inCycleG[x] \]하지만 어떤 \(f\)-사이클에서 alive가 일부만 참이면 그 사이클은 통째로 선택할 수 없으므로 해당 \(f\)-사이클 전체를 제거해야 한다.
그러면 그 사이클에 있던 정점들은 alive에서 빠지고, 이 정점들이 속한 \(g\)-사이클에서도 “일부만 남은 상태”가 되어 연쇄적으로 제거가 발생한다.
이를 위해:
- \(f\)-사이클/ \(g\)-사이클을 각각 분해하고(사이클 id 부여),
- 각 사이클마다 현재
alive정점 수를 카운트한 뒤, - “사이클 크기 != alive 카운트”가 된 사이클을 큐에 넣고 BFS처럼 전파하며
alive를 지운다.
최종적으로 남아있는 alive 정점 수가 최대 선택 가능 열 수 \(K\)이고, 답은 \(N-K\).
알고리즘 설계 (Mermaid)
flowchart TD
A["입력: N, A[1..N], B[1..N], C[1..N]"] --> B["pos[x] = A에서의 위치 구축"]
B --> C["f(x)=B[pos[x]], g(x)=C[pos[x]] 구성"]
C --> D["f에서 위상 제거로 cycle 정점 표시"]
C --> E["g에서 위상 제거로 cycle 정점 표시"]
D --> F["f의 사이클 분해 및 cycleId 부여"]
E --> G["g의 사이클 분해 및 cycleId 부여"]
F --> H["alive[x] = inCycleF[x] and inCycleG[x] 초기화"]
G --> H
H --> I["각 사이클별 alive 개수 카운트"]
I --> J["부분만 alive인 사이클을 큐에 push"]
J --> K["큐 pop -> 해당 사이클 전체 제거정점 삭제를 반대쪽 사이클 카운트에 반영"]
K --> J
K --> L["남은 alive 개수 K 계산"]
L --> M["정답: N-K 출력"]
복잡도 분석
| 항목 | 복잡도 | 비고 |
|---|---|---|
| 사이클 판별(각 그래프) | \(O(N)\) | 진입차수 + 큐(위상 제거) |
| 사이클 분해/전파 | \(O(N)\) | 각 정점/사이클 최대 1회 제거 |
| 전체 시간 복잡도 | \(O(N)\) | \(N \le 10^5\) |
| 공간 복잡도 | \(O(N)\) | 배열/사이클 저장 |
C++ 구현 코드
| |
코너 케이스 및 실수 포인트
| 케이스 | 설명 | 처리 |
|---|---|---|
| 2행/3행 중복이 많음 | 한 값으로 많은 정점이 향할 수 있음 | 사이클 판별은 위상 제거로 안전 |
| 사이클 일부만 교집합 | \(f\) 사이클 내에 \(g\) 비사이클 정점이 섞임 | 사이클 단위 “통째 제거” 전파가 필요 |
| N=1 | 한 열만 존재 | 항상 0 출력 (사이클 조건도 만족) |
| 모두 제거되는 경우 | 교집합이 비어 있음 | kept=0, 답은 N |
![Featured image of post [Algorithm] C++ 백준 2988번: 아보가드로](/post/algorithm/2025-12-19-boj-2988-avogadro-cpp-solution/wordcloud_hu_6fc4219eea35367a.png)
![[Algorithm] C++ 백준 25201번: 보드 뒤집기 게임](/post/algorithm/2025-12-19-boj-25201-board-flipping-game-cpp-solution/wordcloud_hu_22b1d8c414e9b6d9.png)
![[Algorithm] C++ 백준 2586번: 소방차](/post/algorithm/2025-12-19-boj-2586-firetruck-cpp-solution/wordcloud_hu_c7df555f7b0ecd9e.png)
![[Algorithm] C++ 백준 2988번: 아보가드로](/post/algorithm/2025-12-19-boj-2988-avogadro-cpp-solution/wordcloud_hu_504f3f1bc728ef52.png)
![[Algorithm] C++ 백준 3006번: 터보소트](/post/algorithm/2025-12-19-boj-3006-turbosort-cpp-solution/wordcloud_hu_cd4b400156e60fdb.png)
![[Algorithm] C++ 백준 32115번: 돌 놓기 게임](/post/algorithm/2025-12-19-boj-32115-stone-placing-game-cpp-solution/wordcloud_hu_b5570483586eb270.png)
![[Algorithm] C++ 백준 17965번: Absolute Game](/post/algorithm/2025-12-19-boj-17965-absolute-game-cpp-solution/wordcloud_hu_f6800a55fcd520be.png)
![[Algorithm] C++ 백준 1185번: 유럽여행](/post/algorithm/2025-12-19-boj-1185-europe-travel-mst-kruskal-cpp-solution/wordcloud_hu_a7973902548ef27b.png)
![[Algorithm] C++ 백준 32190번: Ian Sequences](/post/algorithm/2025-12-19-boj-32190-ian-sequences-cpp-solution/wordcloud_hu_266416599cd1461b.png)
![[Algorithm] C++ 백준 1777번: 순열복원](/post/algorithm/2025-12-19-boj-1777-permutation-recovery-cpp-solution/wordcloud_hu_e783e8b2198c2957.png)