💻코딩테스트

[이코테_코딩테스트] 다이나믹 프로그래밍 기초 문제 풀이 - 1

date
Aug 2, 2023
slug
coding-test-dynamic-programming-example-1
author
status
Public
tags
Python
코딩테스트
summary
다이나믹 프로그래밍 문제를 풀어보자
type
Post
thumbnail
category
💻코딩테스트
updatedAt
Aug 2, 2023 09:22 AM

[문제] 개미 전사

  • 개미 전사는 부족한 식량을 충당하고자 메뚜기 마을의 식량창고를 몰래 공격하려고 합니다. 메뚜기 마을에는 여러 개의 식량창고가 있는데 식량창고는 일직선으로 이어져 있습니다.
  • 각 식량창고에는 정해진 수의 식량을 저장하고 있으며 개미 전사는 식량창고를 선택적으로 약탈하여 식량을 빼앗을 예정입니다. 이때 메뚜기 정찰병들은 일직선상에 존재하는 식량창고 중에서 서로 인접한 식량창고가 공격받으면 바로 알아챌 수 있습니다.
  • 따라서 개미 전사가 정찰병에게 들키지 않고 식량창고를 약탈하기 위해서는 최소한 한 칸 이상 떨어진 식량창고를 약탈해야 합니다.
notion image
  • 예를 들어 식량창고 4개가 다음과 같이 존재한다고 가정합시다.
{1, 3, 1, 5}
  • 이때 개미 전사는 두 번째 식량창고와 네 번째 식량창고를 선택했을 때 최댓값인 총 8개의 식량을 빼앗을 수 있습니다. 개미 전사는 식량창고가 이렇게 일직선상일 때 최대한 많은 식량을 얻기를 원합니다.
  • 개미 전사를 위해 식량창고 N개에 대한 정보가 주어졌을 때 얻을 수 있는 식량의 최댓값을 구하는 프로그램을 작성하세요.
 

[문제] 개미 전사 - 문제 조건

notion image
 

[문제] 개미 전사 - 문제 해결 아이디어

  • 번째 식량창고까지의 최적의 해 (얻을 수 있는 식량의 최댓값)
    • 이렇게 정의하면 다이나믹 프로그래밍을 적용할 수 있다.
        1. 최적 부분 구조 (Optimal Substructure)
            • 큰 문제를 작은 문제로 나눌 수 있으며 작은 문제의 답을 모아 큰 문제를 해결할 수 있다.
        1. 중복되는 부분 문제 (Overlapping Subproblem)
            • 동일한 작은 문제를 반복적으로 해결해야 한다.
notion image
  • 왼쪽부터 차례대로 식량창고를 턴다고 했을 때, 특정한 i번째 식량창고에 대해서 털지 안 털지의 여부를 결정하면, 아래 2가지 경우 중 더 많은 식량을 털 수 있는 경우를 선택하면 된다.
notion image
  • 번째 식량창고까지의 최적의 해 (얻을 수 있는 식량의 최댓값)
  • 번째 식량창고에 있는 식량의 양
  • 점화식은 아래와 같다.
  • 한 칸 이상 떨어진 식량창고는 항상 털 수 있으므로 (i - 3)번째 이하는 고려할 필요가 없다.
 

[문제] 개미 전사 - 나의 답안 (Python)

n = int(input()) k_list = list(map(int, input().split())) d = [0] * n d[0] = k_list[0] d[1] = max(k_list[0], k_list[1]) for i in range(2, n): if d[i - 2] + k_list[i] < d[i - 1]: d[i] = d[i - 1] else: d[i] = d[i - 2] + k_list[i] print(d[n - 1])
 

[문제] 개미 전사 - 답안 예시 (Python)

# 정수 N을 입력 받기 n = int(input()) # 모든 식량 정보 입력 받기 array = list(map(int, input().split())) # 앞서 계산된 결과를 저장하기 위한 DP 테이블 초기화 d = [0] * 100 # 다이나믹 프로그래밍(Dynamic Programming) 진행 (보텀업) d[0] = array[0] d[1] = max(array[0], array[1]) for i in range(2, n): d[i] = max(d[i - 1], d[i - 2] + array[i]) # 계산된 결과 출력 print(d[n - 1])
  • 다이나믹 프로그래밍 문제 풀이를 위해서는 먼저 적용 가능한지 여부를 파악하고, 점화식을 어떻게 세울지가 관건인 것 같다.
  • 나의 답안 중 for 문 내부에서 if ~ else 문을 통한 비교를 하지 않고, 단순히 max()만 쓰면 되는 것을 기억해야겠다.
 

[문제] 1로 만들기

  • 정수 X가 주어졌을 때, 정수 X에 사용할 수 있는 연산은 다음과 같이 4가지입니다.
      1. X가 5로 나누어 떨어지면, 5로 나눕니다.
      1. X가 3으로 나누어 떨어지면, 3으로 나눕니다.
      1. X가 2로 나누어 떨어지면, 2로 나눕니다.
      1. X에서 1을 뺍니다.
  • 정수 X가 주어졌을 때, 연산 4개를 적절히 사용해서 값을 1로 만들고자 합니다. 연산을 사용하는 횟수의 최솟값을 출력하세요. 예를 들어 정수가 26이면 다음과 같이 계산해서 3번의 연산이 최솟값입니다.
    • 26 → 25 → 5 → 1
 

[문제] 1로 만들기 - 문제 조건

notion image
 

[문제] 1로 만들기 - 문제 해결 아이디어

  • 피보나치 수열 문제를 도식화한 것처럼 함수가 호출되는 과정을 그림으로 그려보면 다음과 같다.
notion image
  • 를 1로 만들기 위한 최소 연산 횟수
  • 단, 1을 빼는 연산을 제외한 나머지는 해당 수로 나누어떨어질 때에 한해 점화식을 적용할 수 있다.
 

[문제] 1로 만들기 - 답안 예시 (Python)

x = int(input()) # 각 인덱스 i번째에는 숫자 i를 1초 만들 수 있는 최솟값이 들어간다고 해보자. d = [0] * 30001 for i in range(2, x + 1): # 1 빼는 경우 d[i] = d[i - 1] + 1 # 2로 나누어 떨어지는 경우 if i % 2 == 0: d[i] = min(d[i], d[i // 2] + 1) # 3으로 나누어 떨어지는 경우 if i % 3 == 0: d[i] = min(d[i], d[i // 3] + 1) # 5로 나누어 떨어지는 경우 if i % 5 == 0: d[i] = min(d[i], d[i // 5] + 1) print(d[x])
 
 

이 글은 유튜브 “동빈나” 채널의 “(이코테 2021 강의 몰아보기) 6. 다이나믹 프로그래밍” 영상을 보고 작성하였습니다.