3 분 소요

Dynamic Programming

이코테 8-2

문제

  • 1로 만들기

    정수 x가 주어질 때 사용할 수 있는 연산은 4가지이다

    1. 5로 나누어떨어지면 5로 나눔

    2. 3으로 나누어떨어지면 3으로 나눔

    3. 2로 나누어떨어지면 2로 나눔

    4. 1을 뺀다

    정수 x를 1로 만들려고 할 때 사용하는 연산의 최솟값을 출력하시오

  • 설명

    이 문제는 Dynamic Programming의 잘 알려진 예제 중 하나로, memoization 기법을 이용해 숫자 1의 최소 연산 횟수를 시작으로 bottom-up 방식(상향식)으로 계산을 해나가서 원하는 숫자의 최소 연산 횟수를 구한다.

풀이 및 아이디어

기록을 남겨두는 배열의 이름을 dp라고 하자.

dp[1] = 0 : 1이 주어졌을 때, 1이 되기위한 최소 연산 횟수는 0이다.

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

dp[2]에 해당하는 두 식이 수학적으로 봤을 때 의미는 같지만, 문제를 보면 2에서 1이 되기 위해 어떻게 했는지 중간과정을 나타내는 식이다. 첫번째 식은 -1 연산, 두번째 식은 /2 연산을 수 행했을 때이다. 이런식으로 1을 뺐을 때 또는 나누어 떨어지는 수가 있다면 나눗셈을 했을 때 횟수를 각각 구해서 둘 중 작은 값을 선택하면 된다.

public class DP {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int x = sc.nextInt();
        int[] dp = new int[x + 1];
        
        for (int i = 2; i < x + 1; i++) {
            dp[i] = dp[i - 1] + 1; // -1 연산
            
            if (i % 5 == 0) {
                dp[i] = Math.min(dp[i], dp[i / 5] + 1);
            }
            
            if (x % 3 == 0) {
                dp[i] = Math.min(dp[i], dp[i / 3] + 1);
            }
            
            if (x % 2 == 0) {
                dp[i] = Math.min(dp[i], dp[i / 2] + 1);
            }
        }
        
        System.out.println(dp[x]);
    }
}

이코테 8-3

문제

개미 전사는 부족한 식량을 충당하고자 메뚜기 마을의 식량창고를 몰래 공격하려고 한다.

메뚜기 마을에는 여러 개의 식량창고가 있는데 식량 창고는 일직선으로 이어져있다.

각 식량창고에는 정해진 수의 식량을 저장하고 있으며 개미 전사는 식량창고를 선택적으로 약탈하여 식량을 빼앗을 예정이다.

이때 메뚜기 정찰병들은 일직선상에 존재하는 식량창고 중에서 서로 인접한 식량창고가 공격받으면 바로 알아챌수있다.

따라서 개미 전사가 정찰병에게 들키지 않고 식량창고를 약탈하기 위해서는 최소한 한 칸 이상 떨어진 식량 창고를 약탈해야 한다.

{1, 3, 1, 5} 식량창고 4개가 존재한다고 가정했을 때

두번째, 네번째 식량창고를 선택했을 때 최대 8개의 식량을 빼앗을 수 있다.

풀이 및 아이디어

식량의 갯수 리스트 : food

dp 리스트 : dp라고 하자.

  1. dp[0]

    무조건 food[0]이다.

  2. dp[1]

    0번째가 더 많아서 0번쨰를 털었다면 food[0], 아니면 food[1]이 될 것이다.

  3. dp[2]

    1) i = 1 창고를 털었다면 i = 2 창고는 털지 못하므로 dp[2]는 dp[1]의 값과 같다.

    2) i = 1 창고를 털지 않았다면 i = 0 창고를 털었으므로 dp[0] + food[2]의 값이 된다.

  4. dp[i]

    3번의 논리를 계속해서 이어나간다. i - 1번째 창고를 턴 경우, i번째를 털 수 없다. 즉, dp[i] = dp[i - 1]

    i - 2번째 창고를 턴 경우, 현재 창고를 턴다.

    dp[i] = dp[i - 2] + food[i]

import java.util.Scanner;
public class DP {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] dp = new int[n];
        int[] foodArr = new int[n];
        
        for (int i = 0; i < n; i++) {
            foodArr[i] = sc.nextInt();
        }
        
        dp[0] = foodArr[0];
        dp[1] = Math.max(foodArr[0], foodArr[1]);
        for (int i = 2; i < n; i++) {
			dp[i] = Math.max(dp[i - 1], d[i - 2] + foodArr[i]);
        }
        
        System.out.println(dp[n - 1]);
    }
}

이코테 8-5

N가지 종류의 화폐가 있다. 이 화폐들의 개수를 최소한으로 이용해서 그 가치의 합이 M원이 되도록 하려고 한다.

이때 각 종류의 화폐는 몇개라도 사용할 수 있다.

예를 들어, 2원, 3원 화폐가 있을 때는 15원을 만들기 위해 3원을 5개 사용하는 것이 가장 최소의 화폐 개수이다.

M원을 만들기 위한 최소한의 화폐 개수를 출력하는 프로그램을 작성하세요

불가능한 경우 -1 출력

이코테 8-6

n x m 크기의 금광이 있다. 금광은 1 x 1 크기의 칸으로 나누어져 있으며, 각 칸은 특정한 크기의 금이 들어있다.

채굴자는 첫번째 열부터 출발하여 금을 캐기 시작한다. 맨 처음에는 첫번째 열의 어느 행에서든 출발할 수 있다. 이후에 m - 1번에 걸쳐서 매번 오른쪽 위, 오른쪽, 오른쪽 아래 3가지 중 하나의 위치로 이동해야 한다. 결과적으로 채굴자가 얻을 수 있는 금의 최대 크기를 출력하는 프로그램을 작성하세요.

댓글남기기