article thumbnail image
Published 2023. 4. 14. 16:37

알고리즘을 공부하면서 똑같은 문제도 여러 가지로 풀 수 있다는 것을 느꼈다.

그리고 각 문제마다 효율적인 방법이 있다.

 

그래서 알고리즘 문제를 풀때 다른 풀이와 내 풀이를 비교하며 어떤게 효율적인지 생각해보는 습관이 좋은 것 같다.

 

 

다음 문제는

백준의 9095번 분제 1,2,3더하기라는 문제이다.

 

n이 11보다 작다는 제한이 주어져서 뭔가 메모이제이션을 이용해서 풀면 굉장히 효율적일 것 같았다.

근데 어떻게 풀지 감이 안와서

 

처음에는 DFS를 이용해서 풀었다.

 

1. DFS 풀이법

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
    static int count;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int tc = Integer.parseInt(br.readLine());

        StringBuilder sb = new StringBuilder();

        while (tc-->0){
            int i = Integer.parseInt(br.readLine());
            count=0;
            sb.append(count(i)).append('\n');
        }
        System.out.println(sb);
    }
    static int count(int i){
        if(i==0) count++;
        if(i>0) count(i-1);
        if(i>1) count(i-2);
        if(i>2) count(i-3);
        return count;
    }
}

1을 더할 경우 2를 더할 경우 3을 경우 세 가지로 나뉘어 가지를 타고 경우의 수를 나눠 들어간 후 해당 숫자가 되면 count를 하나씩 올려주는 것이다.

n의 값이 작고 tc가 작은지 생각보다 시간이 적게 소요됐다.

 

 


 

다른 풀이들을 찾아보니 역시나 dp를 이용해서 푼 경우가 많았다.

dp는 규칙을 찾아 점화식을 만들어내는 것이 중요한 것 같다.

 

즉, n번째 수가 이전의 항들과 어떤 규칙이 있는지를 알아내는 것이다.

 

위 문제에서는

n(n>3)을 1과 2와 3의 합으로 나타낼 때

젤 앞에 1이 오는경우, 2가 오는경우, 3이 오는 경우 3가지가 나올 수 있다.

 

따라서 n을 다음과 같이 나타낼 수 있다.

n = 1 + (n-1)

n = 2 + (n-2)

n = 3 + (n-3)

 

위 식에 따르면 n을 1,2,3의 합으로 나타낼 수 있는 모든 경우의 수

1. 1 과 n-1을 1,2,3의 합으로 나타낼 수 있는 모든 경우의 수

2. 2 와 n-2를 1,2,3 의 합으로 나타낼 수 있는 모든 경우의 수

3. 3 과 n-3을 1,2,3의 합으로 나타낼 수 있는 모든 경우의 수

위 세가지 경우를 합한 경우가 된다.

 

위 규칙을 점화식으로 나타내면 dp[n] = dp[n-1] + dp[n-2] + dp[n-3] 이다.

 

이제 그럼 dp[4] 부터는 계산해서 구할 필요가 없다.

dp[3]까지만 구해주면 된다

 

dp[1] = 1

dp[2] = 2 //1+1, 2

dp[3] = 3 //1+1+1, 1+2, 2+1, 3

로 나타낼 수 있다.

 

이걸 이용해 코드로 나타내면

2.DP를 적용한 풀이법

import java.io.*;

public class Main{
	public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();
        int tc = Integer.parseInt(br.readLine());
        
        int dp[] = new int[11];
        dp[1] = 1;
        dp[2] = 2;
        dp[3] = 4;
        
        for(int i = 4; i < 11; i++)
        	dp[i] = dp[i-1] + dp[i-2] + dp[i-3];
        for(int i = 0; i < tc; i++){
        	int t = Integer.parseInt(br.readLine());
        	sb.append(dp[t] + "\n");
        }
        System.out.println(sb);
    }
}

생각보다 시간이 오래걸린다.

dp 이용하는게 더 효율적일 것 같은데

이 방법은 testcase가 많아질수록 효율적이지 않을까 싶다.

'Algorithm' 카테고리의 다른 글

[Java]Merge sort  (0) 2023.04.20
분할 정복 정복하기~  (2) 2023.04.20
DFS / BFS  (0) 2023.04.14
백준 10814 - 나이순 정렬 JAVA  (0) 2022.11.19
[데일리코딩] 피보나치, 메모이제이션  (0) 2022.11.07
복사했습니다!