Algorithm

[BOJ] 12865. 평범한 배낭

프로그래민 2021. 6. 12. 15:07
반응형

유명한 Knapsack 문제이다.

Knapsack 대표적인 문제이다. 보통 Knapsack 문제를 접근할때는 크게 두가지 방법이 있다. 크게 브루트포스와 dp로 접근할 수 있다.

브루투포스로 접근은 단순하게 고르고, 안고르고를 반복하며 재귀호출하는 방식이다. 이 방식은 시간복잡도가 2^N 이기에 대다수의 문제에서 적용이 힘들다. 이 문제또한 N의 최대값이 100이기에 적용이 불가하지만 한번 코드는 작성해보았다.

1. 브루트 포스(시간초과)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package algostudy2;
 
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class Main_bj_12865_평범한배낭_timeout {
    static int N;
    static int weightLimit;
 
    static int[] weight;
    static int[] value;
 
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
 
        N = Integer.parseInt(st.nextToken());
        weightLimit = Integer.parseInt(st.nextToken());
 
        weight = new int[N];
        value = new int[N];
 
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            weight[i] = Integer.parseInt(st.nextToken());
            value[i] = Integer.parseInt(st.nextToken());
        }
 
        System.out.println(dfs(00));
    }
 
    static int dfs(int depth, int weightSum) {
        if (depth == N) {
            return 0;
        }
 
        int valueSum1 = 0;
        if (weightSum + weight[depth] <= weightLimit) {
            valueSum1 = value[depth] + dfs(depth + 1, weightSum + weight[depth]);
        }
        int valueSum2 = dfs(depth + 1, weightSum);
 
        return Math.max(valueSum1, valueSum2);
    }
}
 
                            

 

다음 방식으로 이 재귀 과정에서 메모이제이션 dp를 활용하는 방식을 사용해보았다. 즉, dp[depth][weight]을 활용하여 만일 한번 탐색된 곳이면 저장 후 이것을 다시 탐색하지 않고 반환해주는 방식을 사용해보았다. 

2. 재귀 + dp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package algostudy2;
 
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class Main_bj_12865_평범한배낭_dp1 {
    static int N;
    static int weightLimit;
 
    static int[] weight;
    static int[] value;
    static int[][] dp;
 
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
 
        N = Integer.parseInt(st.nextToken());
        weightLimit = Integer.parseInt(st.nextToken());
 
        weight = new int[N];
        value = new int[N];
        dp = new int[101][100001];        //i는 물품, j는 무게
 
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            weight[i] = Integer.parseInt(st.nextToken());
            value[i] = Integer.parseInt(st.nextToken());
        }
 
        System.out.println(dfs(00));
    }
 
    static int dfs(int depth, int weightSum) {
        if (dp[depth][weightSum] > 0) {
            return dp[depth][weightSum];
        }
 
        if (depth == N) {
            return 0;
        }
 
        int valueSum1 = 0;
        if (weightSum + weight[depth] <= weightLimit) {
            valueSum1 = value[depth] + dfs(depth + 1, weightSum + weight[depth]);
        }
        int valueSum2 = dfs(depth + 1, weightSum);
 
        dp[depth][weightSum] = Math.max(valueSum1, valueSum2);
        return dp[depth][weightSum];
    }
}
 
                           

 

또 다음 방식으로는 bottom-up 방식의 dp를 활용해보았다. 이 방식은 링크를 보고 적용해본 방식이다.

3. dp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package algostudy2;
 
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class Main_bj_12865_평범한배낭_dp2 {
    static int N;
    static int limitWeight;
 
    static int[] weight;
    static int[] value;
    static int[][] dp;
 
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
 
        N = Integer.parseInt(st.nextToken());
        limitWeight = Integer.parseInt(st.nextToken());
 
        weight = new int[N + 1];
        value = new int[N + 1];
 
        for (int i = 1; i <= N; i++) {
            st = new StringTokenizer(br.readLine());
            weight[i] = Integer.parseInt(st.nextToken());
            value[i] = Integer.parseInt(st.nextToken());
        }
 
        dp = new int[N + 1][limitWeight + 1];
 
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= limitWeight; j++) {
                dp[i][j] = dp[i - 1][j];
 
                if (j - weight[i] >= 0) {    //i번째 물건의 무게를 취할수있다면 비교하기
                    //i번쨰 물건을 안취하는 경우(dp[이전물건][현재무게]) vs i번째 물건을 치하는 경우(dp[이전물건][현재무게-현재물건무게] + 현재물건가치)
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);        //i번째 물건을 안취하는 경우 vs i번째 물건을 취하는 경우
                }
            }
        }
 
        System.out.println(dp[N][limitWeight]);
    }
 
}
 
         

 

반응형

'Algorithm' 카테고리의 다른 글

[BOJ] 11562. 백양로 브레이크  (0) 2021.06.15
[BOJ] 7579. 앱  (0) 2021.06.12
[BOJ] 1937. 욕심쟁이 판다  (0) 2021.06.12
[BOJ] 1520. 내리막 길  (0) 2021.06.12
[Programmers] 광고 삽입  (0) 2021.06.05