알고리즘 문제/백준
[백준] 1010번: 다리 놓기 (Java)
Lpromotion
2024. 8. 26. 20:30
1. 문제설명
도시에는 도시를 동쪽과 서쪽으로 나누는 큰 일직선 모양의 강의 흐르고 있다. 다리를 짓기로 하고, 짓기에 적합한 곳(사이트)이 서쪽에 N개, 동쪽에는 M개가 있다.(N≤M) 한 사이트에는 최대 한 개의 다리만 연결될 수 있고, 다리를 최대한 많이 짓기 위해 서쪽의 사이트 개수만큼(N개) 다리를 지으려고 한다.
다리끼리는 서로 겹쳐질 수 없다고 할 때 다리를 지을 수 있는 경우의 수를 구하는 문제이다.
- 시간 제한: 0.5초
- 메모리 제한: 128MB
2. 접근 방식
- 조합의 개념을 사용한다.
- $_nC_r$ : 서로 다른 n개의 원소에서 r(단, $0< r ≤ n$)개를 중복없이, 순서를 고려하지 않고 선택하는 것
- $_nC_r = {_{n-1}C_{r-1}} + {_{n- 1}C_{r}}$
- `int dp[][]` 배열을 사용하여 조합의 값을 저장한다.
- DP의 Top-Down 방식을 사용한다.
- ${_{n-1}C_{r-1}}$과 ${_{n- 1}C_{r}}$을 재귀 호출을 통해 $_nC_r$의 값을 저장한다.
- n이 r과 같거나, r이 1이면, 해당 배열에 1을 저장하고 반환한다.
- 마지막으로 $_nC_r$의 값을 반환한다.
3. 최종 코드
import java.io.*;
import java.util.*;
public class Main {
static int n, m;
static int[][] dp; // 조합의 값을 저장할 배열
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int t = Integer.parseInt(br.readLine());
while(t-- > 0) {
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());
dp = new int[m+1][m+1]; // dp 배열 초기화
// m개 중에서 n개를 선택하는 조합의 경우의 수를 구함
System.out.println(combination(m, n));
}
}
static int combination(int n, int r) {
// 이미 계산을 한 경우, 그 값을 반환
if(dp[n][r] > 0) return dp[n][r];
// nCn 또는 nC1이면 값은 1로 반환
if(n==r || r==0) return dp[n][r] = 1;
// 재귀 호출을 통해 점화식을 만족하는 조합의 값을 계산
dp[n][r] = combination(n-1, r-1) + combination(n-1, r);
return dp[n][r]; // nCr 값을 반환
}
}
4. 느낀점 or 기억할정보
문제를 보고 조합 개념을 사용하면 된다는 것은 바로 파악했지만, 점화식은 찾아보게 되었다.
반응형