18427번: 함께 블록 쌓기
첫째 줄에 자연수 N, M, H가 공백을 기준으로 구분되어 주어진다. (1 ≤ N ≤ 50, 1 ≤ M ≤ 10, 1 ≤ H ≤ 1,000) 둘째 줄부터 N개의 줄에 걸쳐서 각 학생이 가진 블록들의 높이가 공백을 기준으로 구
www.acmicpc.net
- 132ms
DP
,knapsack
N명의 학생들이 가지고 있는 블록으로 H 높이를 만들 수 있는 경우의 수를 계산하는 문제이다.
이 문제의 핵심은 다음과 같다
- 한 학생당 최대 1개의 블록만 사용가능
- 블록을 사용하지 않아도 됨
3명의 학생이 다음과 같은 높이의 블록을 가지고 있을 때 높이 1부터 h=5까지 만들 수 있는 경우의수를 생각해보자
2 3 5
3 5
1 2 3
1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|
1 | 0 | 1 | 1 | 0 | 1 |
2 | |||||
3 |
첫 번째 학생은 가지고 있는 블록으로 2, 3, 5 높이를 만들 수 있다.
1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|
1 | 0 | 1 | 1 | 0 | 1 |
2 | 0 | 1 | 2 | 0 | 3 |
3 |
두번째 학생이 가지고 있는 블록은 3, 5이다.
두 번째 학생일 때, 높이 3을 만들 수 있는 경우는 자신이 가지고 있는 높이 3 블록1
+ 이전 학생이 높이 3을 만들 수 있는 경우의 수 1
로 2 가된다
높이 5일 때, 이전 학생이 높이 5 - 3 = 2 를 만들 수 있는 경우의 수 1
+ 자신이 가지고 있는 높이 5 블록 1
+ 이전 학생이 높이 5를 만들 수 있는 경우의 수 1
= 3 이 된다. 이전 학생이 높이 2를 만들 수 있는 경우가 있다면 가지고 있는 블록 3을 이용하여 5를 만들 수 있다.
1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|
1 | 0 | 1 | 1 | 0 | 1 |
2 | 0 | 1 | 2 | 0 | 3 |
3 | 1 | 3 | 4 | 3 | 6 |
세번째 학생이 가지고 있는 블록은 1, 2, 3이다.
높이 3을 만들 때, 이전 학생이 높이 3 - 1 = 2 를 만들 수 있는 경우의 수1
+ 이전 학생이 높이 3 - 2 = 1 을 만들 수 있는 경우의 수0
+ 자신이 가지고 있는 높이 3 블록1
+ 이전 학생이 높이 3를 만들 수 있는 경우의 수 2
= 4 가 된다.
높이 5를 만들 때, 이전 학생이 높이 5 - 1 = 4 를 만들 수 있는 경우의 수0
+ 이전 학생이 높이 5 - 2 = 3 을 만들 수 있는 경우의 수2
+ 이전 학생이 높이 5 - 3 = 2 를 만들 수 있는 경우의 수1
+ 이전 학생이 높이 5를 만들 수 있는 경우의 수 3
= 6 이 된다.
따라서 점화식을 세우면 다음과 같다.
1번. j 높이의 블록을 내가 가지고 있는지 → 가지고 있다면 + 1
2번. 이전 학생이 j - (내가 가진 블록의 높이)까지 만들 수 있는 경우의 수
3번. 이전 학생이 j 높이까지 만들 수 있는 경우의 수
i학생이 j 높이의 블록을 만들 수 있는 경우는 위의 경우를 모두 더한 값이 된다.
for (int i = 1; i <= n; i++) {
// i 번 학생이 j 높이를 만들 수 있는지
for (int j = 1; j <= h; j++) {
for(int block : list[i]) {
if( j == block ) dp[i][j]++; // 1번
if(j > block)
dp[i][j] += dp[i-1][j-block]; // 2번
}
dp[i][j] += dp[i-1][j]; // 3번
dp[i][j] %= 10007;
}
}
#소스코드
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int m = Integer.parseInt(st.nextToken());
int h = Integer.parseInt(st.nextToken());
List<Integer>[] list = new ArrayList[n + 1];
for (int i = 1; i <= n; i++) {
st = new StringTokenizer(br.readLine());
list[i] = new ArrayList<Integer>();
while (st.hasMoreTokens())
list[i].add(Integer.parseInt(st.nextToken()));
}
int[][] dp = new int[n + 1][h + 1]; // dp[i][j]: i번 학생이 j 높이를 만들 수 있는 경우의 수 저장
for (int i = 1; i <= n; i++) {
// i 번 학생이 j 높이를 만들 수 있는지
for (int j = 1; j <= h; j++) {
for(int block : list[i]) {
if( j == block ) dp[i][j]++; // 1번
if(j > block)
dp[i][j] += dp[i-1][j-block]; // 2번
}
dp[i][j] += dp[i-1][j]; // 3번
dp[i][j] %= 10007;
}
}
System.out.println(dp[n][h]);
}
}
'Algorithm > Problem Solving' 카테고리의 다른 글
[BOJ/GoldIV] 2056. 작업 - JAVA 자바 (0) | 2024.04.24 |
---|---|
[BOJ/GoldⅣ] 1253. 좋다 - JAVA 자바 (1) | 2024.04.16 |
[BOJ/GoldIII] 9466. 텀 프로젝트 - JAVA 자바 (0) | 2024.03.21 |
[BOJ/GoldIII] 2206. 벽 부수고 이동하기 (0) | 2024.03.14 |
[BOJ/GoldIII] 1943. 동전 분배 - JAVA 자바 (0) | 2024.03.12 |