애드 혹 (Ad Hoc)
정의
애드 혹 (Ad Hoc) 은 범용 알고리즘이 아닌, 그 문제만의 관찰·트릭·창의적 사고로 푸는 문제 유형. 라틴어로 “이 목적을 위한” 이라는 뜻.
정형화된 자료구조나 DP 점화식 없이, 문제를 꼼꼼히 읽고 패턴·대칭·패리티 같은 수학적 성질을 발견하는 것이 핵심.
문제 상황과 동기
알려진 알고리즘 (BFS, DP, 세그트리 등) 이 명확히 적용되지 않는다.
- naive: 단순 시뮬레이션, 브루트포스, O(2^N) 또는 O(N^3) 이상.
- ad hoc: 문제 안의 숨은 성질 (패리티, 주기, 대칭, 경우 분류) 을 찾아 O(1) ~ O(N) 으로 해결.
핵심 통찰: 문제 자체가 힌트. 제약, 입력 범위, 샘플 입출력에서 규칙성을 귀납.
자주 등장하는 PS 위치:
- Codeforces Div2 A~C (관찰 위주)
- IOI, ICPC 의 창의적 문제
- 프로토타이핑, 해커톤 (시간 제약 아래 빠른 아이디어 검증)
시각화
핵심 아이디어
invariant: 문제 조건 자체가 해법의 힌트.
대표 관찰 기법:
- 패리티 (parity): 홀짝 구분. 체스판 색칠, 불변량.
- 대칭 (symmetry): 좌우/상하 대칭, 순환 대칭.
- 극값 (extremal): 최댓값/최솟값이 정답인 경우.
- 경우 분류 (case work): if-else 로 모든 경우를 나눔 (→ 케이스 워크 참고).
- 주기 (periodicity): 반복 패턴 (예: 1,2,3,1,2,3,…).
- 그리디 (greedy): 증명 없이도 직관적으로 최적.
알고리즘
1. 문제 읽기 (2~3회 정독, 제약·샘플 주목)
2. 샘플 입출력 손으로 시뮬레이션
3. 패턴 / 불변량 찾기 (패리티, 대칭, 극값, ...)
4. 가설 세우기 → 반례 찾기
5. 반례 없으면 증명 (또는 "AC 받으면 증명" → submit)
6. 구현 (보통 짧고 단순)
구현
예제: 체스판 색칠 (패리티 관찰)
8×8 체스판에서 (r1, c1) 에서 (r2, c2) 로 나이트(Knight) 이동. 흑백 칸이 번갈아 나오는가?
관찰: 나이트 이동은 항상 다른 색으로 이동. (r + c) % 2 가 플립.
// 체스판 색칠: (r+c) % 2
#include <bits/stdc++.h>
using namespace std;
int main() {
int r1, c1, r2, c2;
cin >> r1 >> c1 >> r2 >> c2;
// 나이트 한 번에 다른 색으로
if ((r1 + c1) % 2 == (r2 + c2) % 2) {
cout << "same color, need even steps\n";
} else {
cout << "different color, need odd steps\n";
}
}1 1 2 3same color, need even steps예제: 구슬 뒤집기 (대칭 관찰)
N개 구슬이 일렬. 좌우 대칭이면 “YES”, 아니면 “NO”.
관찰: a[i] == a[N-1-i] for all i.
// 좌우 대칭 체크, O(N)
#include <bits/stdc++.h>
using namespace std;
int main() {
int n; cin >> n;
vector<int> a(n);
for (auto& v : a) cin >> v;
bool ok = true;
for (int i = 0; i < n / 2; i++) {
if (a[i] != a[n - 1 - i]) ok = false;
}
cout << (ok ? "YES" : "NO") << "\n";
}5
1 2 3 2 1YES예제: 수열 주기 찾기 (periodicity)
수열 1, 2, 3, 1, 2, 3, ... 에서 k번째 수는?
관찰: 주기 3. ans = ((k - 1) % 3) + 1.
// 주기 3, O(1)
#include <bits/stdc++.h>
using namespace std;
int main() {
int k; cin >> k;
cout << ((k - 1) % 3) + 1 << "\n";
}71복잡도
| 항목 | 값 |
|---|---|
| 시간 | 문제마다 다름, 보통 O(1)~O(N) |
| 공간 | 문제마다 다름, 보통 O(1)~O(N) |
| 구현 난이도 | 낮음 (관찰만 맞으면 코드 짧음) |
변형
| 기법 | 설명 |
|---|---|
| 패리티 불변량 | XOR, mod 2 연산으로 상태 추적 |
| 경우 분류 | if-else 나무, 모든 케이스 커버 (→ [[case-work |
| 주기 찾기 | 시뮬레이션 후 규칙 귀납, mod 연산 |
| 대칭 활용 | 좌우/상하 대칭, 회전 대칭 |
| 극값 관찰 | max, min, gcd, lcm 이 정답인 경우 |
| 그리디 휴리스틱 | 증명 없이 직관으로 시도 |
함정
1. 반례 간과
관찰이 틀렸는데도 샘플만 맞아서 AC 로 착각. 엣지 케이스 (N=1, 음수, 0, 최댓값) 수동 검증 필수.
2. 과도한 일반화
“N≤10 인데 DP?” → 오버엔지니어링. ad hoc 은 단순한 if-else 로 충분한 경우가 많다.
3. 증명 없이 제출
관찰이 맞는지 손으로 반례 3~5개 찾아보고 제출. Codeforces 는 강한 프리테스트 덕분에 괜찮지만, 대회에선 WA 패널티.
4. 문제 잘못 읽기
제약 오해 (1-indexed vs 0-indexed, inclusive vs exclusive) 가 ad hoc 에서 치명적. 2~3회 정독.
BOJ 연습 문제
| 번호 | 제목 | 정답률 | 링크 |
|---|---|---|---|
| BOJ 1000 | A+B | - | kokoa-lab |
| BOJ 10817 | 세 수 | - | kokoa-lab |
| BOJ 2920 | 음계 | - | kokoa-lab |
| BOJ 10951 | A+B - 4 (EOF) | - | kokoa-lab |
| BOJ 1212 | 8진수 2진수 | - | kokoa-lab |
참고
이 글의 용어 (3개)
- 그리디 (Greedy)algorithm
- 정의 그리디 (Greedy) 알고리즘은 매 단계마다 국소 최적 (locally optimal) 선택을 하여 전역 최적해 (globally optimal solution) 에 도달…
- 케이스 워크 (Case Work)algorithm
- 정의 케이스 워크 (Case Work) 는 문제를 여러 조건/경우로 분류하여 각각 해결하는 패턴. if-else, switch-case, 의사결정 트리 등으로 구현. 복잡한 조건…
- 해 구성하기 (Constructive)algorithm
- 정의 해 구성하기 (Constructive Algorithm) 는 답의 존재를 증명하는 대신, 명시적으로 답을 만드는 문제 유형. "가능한가?" → YES/NO 가 아니라, "가…
💬 댓글