BOJ 7579 앱 Python

이지훈·2023년 4월 24일
0

https://www.acmicpc.net/problem/7579
앱 개발자로서 흥미로웠던 문제

문제에서 요구하는 것)
메모리를 M 만큼 확보하기 위해, 필요한 최소 비용

dp 문제를 많이 풀어 본 사람들이라면 이 문제가 냅색 문제라는 것을 알 수 있을 것이다.


(살짝 어색하다고 느껴지는 이유는, 최대가 아니라 최소 비용을 구하라고 하는점..)

쨌든! 냅색으로 문제를 접근한다면, 무엇을 무게, 무엇을 가치라고 할 것인지 먼저 정의해야한다.

우선,
비용을 최소한으로 사용하여, 최대한 많은 메모리를 확보하는 문제라고 생각해보자.

비용 -> 무게(weight),
메모리 -> 가치(value)

그렇다면 메모리를 확보한 양이 같을때, 비용을 적게 쓸수록 좋다.

문제에서 주어진 예제를 통해 확인해보면

(30, 3), (10, 0), (20, 3) 를 골라 6의 비용으로 총 60의 메모리를 확보한 케이스가
(20, 5), (40, 4) 를 골라 9의 비용으로 총 60의 메모리를 확보한 케이스보다 좋다고 할 수 있다.

그러면 dp 점화식을 세워보도록 하자.

dp[i][j] -> i번째 앱까지 고려하여, j만큼의 메모리를 확보할때 필요한 최소 비용

-> 아쉽게도, 메모리의 범위(1 <= m <=10,000,000)가 너무 크기 때문에,메모리가 dp테이블내에 포함된다면, 모든 케이스를 채우는데에 시간초과, 메모리 초과가 발생한다는 것을 예상할 수 있다.
(앱의 최대 개수 100, 메모리 최대 1000만 -> 100 x 1000만 = 10억)

따라서 불가능 하다...

그렇다면 어떻게 해야할까?

메모리를 가치(value). 비용을 무게(weight)로 생각해보자.

dp[i][j] -> i번째 앱까지 고려하여, j만큼의 비용(무게)을 사용할때 얻을 수 있는 최대 메모리(가치)

우선 '최대' 메모리를 구한다는 점에서, 우리가 항상 풀어왔던 냅색의 문제 정의와 유사해졌다는 것을 확인할 수 있다.

(또한, 앱의 개수의 범위는 1 <= N <= 100, 각 앱을 비활성화 했을 경우의 비용의 범위는 1 <= c <= 100 이기 때문에 메모리는 충분하다.)


import sys


si = sys.stdin.readline

# Tabulation
def preprocess():
    for i in range(1, n + 1):
        for j in range(10001):
        	# i번째 앱의 비용이 j 보다 클 경우 
            if cost[i] > j:
            	# i번째 앱은 고를 수 없다. 
                dp[i][j] = dp[i - 1][j]
            # i번째 앱의 비용이 j 보다 같거나 작을 경우
            else:
            	# i번째 앱을 고르지 않은 경우와, 고른 경우 중 확보할 수 있는 메모리가 더 큰 쪽으로 점화식을 갱신 
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - cost[i]] + memory[i])


def solution():
    for j in range(10001):
    	# n 개의 앱을 모두 고려한 경우, 
        # 가장 적은 양의 비용(j)으로 m 이상의 메모리를 확보할 수 있는 경우를 찾음 
        if dp[n][j] >= m:
        	# 찾았다면 그것이 원하는 값(주어진 메모리를 확보할 수 있는 최소 비용) 
            print(j)
            return


n, m = map(int, si().split())
memory = [0] + list(map(int, si().split()))
cost = [0] + list(map(int, si().split()))


# dp[i][j] -> i번째 인덱스의 앱까지 고려했을때 비용 j 만큼 사용하여 얻을 수 있는 최대 메모리

# 10001로 설정해야 하는 이유:
# 각각의 비용은 범위는 1 ≤ c ≤ 100 이다
# 앱의 개수의 범위는 1 ≤ n ≤ 100 이다
# 따라서 비용의 총 합의 범위는 10000 이하이다.
# 미리 dp 배열의 모든 값을 채워버린 후에 원하는 값(답)을 찾는 방식이므로 
# 배열의 범위(최대 값)를 찾는게 중요하다.
dp = [[0 for _ in range(10001)] for _ in range(n + 1)]

preprocess()
solution()

문제의 요구 조건은 'm 만큼의 메모리를 확보하기 위한 최소 비용 c 를 구하는 것'이지만(진짜 문제),

이를 뒤집어 '주어진 i개의 앱을 모두 고려하여 비용을 j 만큼 사용 할 때, 얻을 수 있는 최대 메모리'라고 문제를 다시 정의(가짜 문제)하여 문제를 풀이 할 수 있었다.

메모리를 m 이상 확보할 수 있는 비용 j가 존재한다면, 그 j 들 중 가장 작은 값이 c 이기 때문이다.

profile
실력은 고통의 총합이다. Android Developer

0개의 댓글