현재 N개의 앱, A1, ..., AN이 활성화 되어 있다고 가정하자. 이들 앱 Ai는 각각 mi 바이트만큼의 메모리를 사용하고 있다. 또한, 앱 Ai를 비활성화한 후에 다시 실행하고자 할 경우, 추가적으로 들어가는 비용(시간 등)을 수치화 한 것을 ci 라고 하자. 이러한 상황에서 사용자가 새로운 앱 B를 실행하고자 하여, 추가로 M 바이트의 메모리가 필요하다고 하자. 즉, 현재 활성화 되어 있는 앱 A1, ..., AN 중에서 몇 개를 비활성화 하여 M 바이트 이상의 메모리를 추가로 확보해야 하는 것이다. 여러분은 그 중에서 비활성화 했을 경우의 비용 ci의 합을 최소화하여 필요한 메모리 M 바이트를 확보하는 방법을 찾아야 한다.
다이나믹 프로그래밍
배낭 문제
처음에는 m
을 이용하여 DP
배열을 만들려고 했지만, m
의 범위가 너무 넓으니 그렇게 해서는 안된다. 따라서 다른 방법으로 DP
배열을 구축해야하는데, 바로 최소 비용을 이용하면 되겠다.
배열의 인덱스를 최소 비용으로 해서, 각 최소 비용별로 확보할 수 있는 최대의 메모리를 넣으면 된다. 1차원 배열로 구축해도 되지만, 나는 2차원 배열로 구축해보았다. dp[i][j]
는, 0~j
번째 메모리까지 사용하여 i
의 비용으로 확보하는 최대 메모리가 된다. 그리고 DP
배열을 순차적으로 탐색하며 m
보다 큰 값이 있을 경우 해당 DP
의 i
가 최소 비용으로 답이 된다.
dp[[i][j]
는 우선 dp[i][j - 1]
을 포함한다. 즉, dp[i][j]
는 dp[i][j]
보다 dp[i][j - 1]
이 더 크다면 dp[i][j - 1]
이 들어가야 한다. 또한, 비용을 c
배열, 확보되는 메모리를 a
배열로 가정할 경우, dp[i][j]
에서, dp[i - c[j]][j] + a[j]
도 비교하여 최대값을 넣어주어야 한다. 결국 j
번째 앱을 해제하여, c[j]
의 비용으로 a[j]
의 메모리를 확보할 경우, dp[i-c[j]][j-1]
의 비용에 a[j]
의 비용을 합한 것과 그렇지 않은 것(dp[i][j]
)를 비교하여 최댓값을 넣어야 하기 때문이다.
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int n, m;
int dp[10001][100];
vector<int> a, c;
int main()
{
int in, s = 0;
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
scanf("%d", &in);
a.push_back(in);
}
for (int i = 0; i < n; i++) {
scanf("%d", &in);
s += in;
c.push_back(in);
}
for (int i = 0; i < n; i++) {
for (int j = 0; j <= s; j++) {
dp[j][i] = max(dp[j][i], dp[j][i - 1]);
if(c[i] <= j)
dp[j][i] = max(dp[j][i], dp[j - c[i]][i - 1] + a[i]);
}
}
for (int i = 0; i <= s; i++) {
for (int j = 0; j < n; j++) {
if (dp[i][j] >= m) {
printf("%d", i);
return 0;
}
}
}
}