본문 바로가기
백준

[백준, Java] 28437번, 막대 만들기, (DP)

by 열정적인 이찬형 2024. 3. 25.

문제 링크

 

28437번: 막대 만들기

첫 줄에 $Q$개의 수를 공백으로 구분해 출력합니다. $i$번째 수는 길이가 $L_i$인 막대를 만드는 방법의 수입니다. 가능한 모든 입력에 대해 답이 $10^9$을 넘지 않음을 증명할 수 있습니다.

www.acmicpc.net


주의사항

  • JAVA를 사용하여 프로그램을 사용하였습니다.
  • 백준에서 코드를 작성하였을 때 아래 형태에서 Main에서 결과가 출력되어야 합니다.
public class Main{ 	
	public static void main(String[] args){
    }
}


문제 설명


 

접근 방법

이 문제에 핵심

 

1. 기본으로 사용할 막대는 N개가 있으며, 각각 길이가 다릅니다.

2. 각 막대를 길이를 양의 정수 k을 설정해서 늘릴 수 있습니다.

3. Q개의 주어진 길이가 존재할 때 막대들을 해당 길이로 만들 수 있는 방법을 결과로 출력합니다.

 

알고리즘 진행 순서.

 

1. 입력된 정보를 저장합니다.

 

2. DP을 통해서 중복되는 연산을 최소화하여 각 길이를 막대로 만드는 방법을 탐색합니다.

 

3. 탐색을 통해 얻은 방법의 개수를 결과로 출력합니다.

 

막대 길이 구하기

 

기본 막대의 길이는 항상 늘리지 않고 만들 수 있는 길이입니다.
 
 
즉, 기본 막대기의 길이는 항상 만들 수 있기 때문에 방법의 값이 기본 1 이상입니다.
 
 

이후, 기본 막대기를 늘려서 만드는 방법에 대해서 알아보자.

 

만약, 기본 막대기의 길이가 2일 때

 

늘려서 만들 수 있는 길이 :  4, 6, 8, 10, 12

 

기본 막대기가 3일 때

 

늘려서 만들 수 있는 길이 : 6, 9, 12, 18

 

중요한 것은 방법의 개수를 구하는 것이므로써 기존의 6을 만들 수 있는 방법의 수가 3개이면 다음 배수들을 만들 수 있는 경우는 모두 +3을 해주어야 합니다.

 

 
Why?
 
6을 시작으로 파생되는 배수이기 때문에, ( 2 X 3, 3 X 2, 6)이면 파생되는 배수는
 
2 X 3 X 2
 
2 X 3 X 3
 
...
 
 
3 X 2 X 2
 
3 X 2 X 3
 
...
 
 
6 X 2
 
6 X 3
 
...
 
 
위처럼 진행되기 떄문에, 배수의 시작되는 방법 개수를 순차적으로 더해주면 됩니다.
 
※예제 입력을 푸는 과정을 확인하시면 이해하기 편하실 것입니다.

 

예제입력 1.

 

1. 입력된 정보를 저장합니다.

 

N : 5

 

1 2 3 4 5

 

Q : 6

 

1 2 3 4 5 6

 

2. DP을 통해서 중복되는 연산을 최소화하여 각 길이를 막대로 만드는 방법을 탐색합니다.

 

 

원래는 길이의 최대값 100,000까지 구해야 하지만, 편의상 10까지 구하겠습니다.
 
1 2 3 4 5 6 7 8 9 10
0 0 0 0 0 0 0 0 0 0
 
 

기본 막대기 설정

 

1 2 3 4 5 6 7 8 9 10
1 1 1 1 1 0 0 0 0 0

 

 
1의 배수일 때
 
1을 만들 수 있는 방법의 수 : 1개

 

1 2 3 4 5 6 7 8 9 10
1 2 2 2 2 1 1 1 1 1
 
2의 배수일 때
 
2을 만들 수 있는 방법의 수 : 2개

 

1 2 3 4 5 6 7 8 9 10
1 2 2 4 2 3 1 3 1 3

 

3의 배수일 때

 
3을 만들 수 있는 방법의 수 : 2개

 

1 2 3 4 5 6 7 8 9 10
1 2 2 4 2 5 1 3 3 3

 

4의 배수일 때

 
4을 만들 수 있는 방법의 수 : 4개

 

1 2 3 4 5 6 7 8 9 10
1 2 2 4 2 5 1 7 3 3

 

....

 

1 2 3 4 5 6 7 8 9 10
1 2 2 4 2 5 1 7 3 5
 
 

3. 탐색을 통해 얻은 방법의 개수를 결과로 출력합니다.

 

Q개의 구해야 하는 길이 : {1, 2, 3, 4, 5, 6}

 

1 2 3 4 5 6 7 8 9 10
1 2 2 4 2 5 1 7 3 5

 

 

 
1 2 2 4 2 5 결과로 출력합니다.
 
 

 

  • BufferedReader를 사용하여 입력되는 정보를 저장합니다.
  • StringTokenizer를 이용하여 막대의 정보를 띄어쓰기 기준 나누었습니다.
  • 점화식을 통한 각 길이에 따른 막대 만드는 방법의 개수를 탐색합니다.
  • 각 목표 길이에 맞는 방법의 개수를 Bufferedwriter 저장합니다.
  • BufferedWriter에 저장된 결과를 출력합니다.

결과코드

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        //입력값 처리하는 BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        //결과값 출력하는 BufferedWriter
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        int N = Integer.parseInt(br.readLine());
        //막대 길이에 따른 방법 저장할 배열
        int[] DP = new int[1000001];
        //기본 막대기 정보 저장 배열
        int[] basicStick = new int[N];
        StringTokenizer st = new StringTokenizer(br.readLine()," ");
        //기본 막대기 정보 저장
        for(int i=0;i<N;i++){
            basicStick[i] = Integer.parseInt(st.nextToken());
            DP[basicStick[i]] = 1;
        }
        //길이에 따른 막대 만들 수 있는 방법 구하기
        for(int i=1;i<=50000;i++){
            for(int j=2;i*j <=100000;j++){
                DP[i*j] = DP[i*j] + DP[i];
            }
        }
        //만들어야 하는 막대의 길이 입력
        int Q = Integer.parseInt(br.readLine());
        st  = new StringTokenizer(br.readLine(), " ");
        //입력받아야 하는 길이에 따른 방법 개수 BufferedWriter 저장
        for(int i=0;i<Q;i++){
            int idx = Integer.parseInt(st.nextToken());
            bw.write(String.valueOf(DP[idx]));
            bw.write(" ");
        }
        bw.flush();		//결과 출력
        bw.close();
        br.close();
    }
}

 

 

 

댓글