문제 설명
가장 윗줄에 1부터 N까지의 숫자 중 서로 다른 N개의 숫자가 한 개씩 적혀 있고, 그 아래줄부터 위 두 수를 더한 값이 저장되는 방식으로 삼각형을 만든다. 예를 들어 N=4이고 윗줄이 3 1 2 4이면 다음과 같다.
3 1 2 4
4 3 6
7 9
16
가장 아랫줄의 값 F가 주어질 때 윗줄에 어떤 숫자를 배치해야 이 삼각형의 최하단 값이 F가 되는지 구하는 문제이다.
답이 여러 개인 경우 사전순으로 가장 앞서는 배열을 출력한다.
입력 & 출력
입력
- 첫 줄: 두 개의 정수 N, F (1 ≤ N ≤ 10, F ≤ 1,000,000)
출력
- 조건을 만족하는 수열을 사전순으로 출력 (공백 구분)
예제 입력 & 출력
예제 입력
4 16
예제 출력
3 1 2 4
해결 방법
파스칼의 삼각형 구조 활용
맨 마지막 줄의 수는 맨 윗줄의 숫자 각각에 파스칼 삼각형의 조합 계수를 곱한 합으로 계산된다.
F = p[0]*C(n-1,0) + p[1]*C(n-1,1) + ... + p[n-1]*C(n-1,n-1)
- 여기서 p[i]는 맨 윗줄의 수열의 i번째 수
- C(n-1, i)는 이항계수
해결 순서
- C(n-1, i) 조합 계수 배열 b[]를 미리 구한다.
- 1부터 N까지의 수 중에서 중복 없이 순열을 구성한다.
- DFS로 순열을 탐색하며, 현재 수열 × 조합값의 합이 F인지 확인
- 조건을 만족하면 출력하고 탐색 종료 (사전순으로 가장 앞선 순열)
예제로 공식 이해하기
예제 입력이 N = 4, F = 16일 때 정답 수열 중 하나는 p = [3, 1, 2, 4]이다. 이 수열을 공식에 대입하면 다음과 같이 계산된다:
F = 3*C(3,0) + 1*C(3,1) + 2*C(3,2) + 4*C(3,3)
= 3*1 + 1*3 + 2*3 + 4*1
= 3 + 3 + 6 + 4
= 16
코드 구현 (Java)
import java.util.Scanner;
public class Problem8 {
static int[] b, p, ch;
static int n, f;
boolean flag = false;
int[][] dy = new int[35][35];
public int combi(int n, int r) {
if (dy[n][r] > 0) return dy[n][r];
if (n == r || r == 0) return 1;
return dy[n][r] = combi(n - 1, r - 1) + combi(n - 1, r);
}
public void DFS(int L, int sum) {
if (flag) return; // 사전순 먼저 발견 시 종료
if (L == n) {
if (sum == f) {
for (int x : p) System.out.print(x + " ");
flag = true;
}
} else {
for (int i = 1; i <= n; i++) {
if (ch[i] == 0) {
ch[i] = 1;
p[L] = i;
DFS(L + 1, sum + p[L] * b[L]);
ch[i] = 0;
}
}
}
}
public static void main(String[] args) {
Problem8 T = new Problem8();
Scanner kb = new Scanner(System.in);
n = kb.nextInt();
f = kb.nextInt();
b = new int[n]; // 조합계수
p = new int[n]; // 순열 저장
ch = new int[n + 1]; // 중복 체크
for (int i = 0; i < n; i++) {
b[i] = T.combi(n - 1, i);
}
T.DFS(0, 0);
kb.close();
}
}
코드 설명
조합 계수 생성
b[i] = combi(n - 1, i);
- 맨 윗줄의 각 숫자에 곱할 파스칼 삼각형의 이항계수
DFS 탐색
DFS(L + 1, sum + p[L] * b[L]);
- 순열을 완성하며 현재까지의 누적합을 계산
- 마지막 줄 합이 f와 같으면 정답
사전순 조건 처리
if (flag) return;
- 조건을 만족하는 수열을 하나 찾으면 이후 탐색 중단
- 처음 찾은 게 사전순 가장 앞선 순열
시간 복잡도 분석
- DFS 순열 생성은 O(N!)
- 하지만 조기 종료 조건(flag) 덕분에 사전순 첫 정답에서 바로 종료된다.
- 조합 계산은 O(N²) → 메모이제이션으로 최적화
출처: 인프런 자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비
https://www.inflearn.com/course/자바-알고리즘-문제풀이-코테대비/dashboard
자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비 강의 | 김태원 - 인프런
김태원 | , 자바(Java) 알고리즘 문제풀이 채점사이트를 통해 기초부터 준비해보세요! 💪 [사진] 이 강의는 [사진] 자바(Java)로 코딩테스트 준비를 하고 계신 분께 추천드려요! 문제는 기초~ 중급
www.inflearn.com
'코딩테스트 > 자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비' 카테고리의 다른 글
| 섹션 8 DFS, BFS - 10. 미로탐색(DFS) (1) | 2025.05.26 |
|---|---|
| 섹션 8. DFS, BFS 활용 - 9. 조합 구하기 (1) | 2025.05.23 |
| 섹션 8 DFS, BFS - 7. 조합의 경우수(메모이제이션) (1) | 2025.05.14 |
| 섹션 8 DFS, BFS - 6. 순열 구하기 (0) | 2025.05.14 |
| 섹션 8 DFS, BFS - 5. 동전교환 (0) | 2025.05.14 |