Нехай dp_k[s] — максимальна вартість вантажу вагою не більше , якщо дозволено використовувати лише предмети перших типів.
Розглянемо два можливих варіанти при складанні вантажу вагою :
Не використовувати предмет -го типу: в цьому випадку оптимальне значення не зміниться, тобто
Використовувати предмет -го типу: тоді його вага w_k займе частину місткості рюкзака, а вартість збільшиться на v_k, тобто
Оскільки потрібно максимізувати вартість вантажу, отримуємо рекурентне співвідношення:
Базові випадки:
Нехай функція f(k, s) обчислює максимальну вартість вантажу, який можна зібрати в рюкзак вагою не більше , використовуючи перші типів предметів. Тоді має місце рекурентне співвідношення:
Залишилося обчислити значення функції f(k, s) використовуючи мемоізацію.
Реалізація алгоритму
Оголосимо робочі масиви:
— вага предмета -го типу;
— вартість предмета -го типу;
— максимальна вартість вантажу вагою не більше ;
#define MAXW 252
#define MAXN 37
int w[MAXN], p[MAXN];
int dp[MAXW];Читаємо вхідні дані.
scanf("%d %d", &s, &n);
for (i = 0; i < n; i++)
scanf("%d %d", &w[i], &p[i]);Послідовно обробляємо типів предметів.
for (k = 0; k < n; k++)
{Перераховуємо значення масиву , враховуючи можливість використання предметів типу . Оскільки кількість предметів кожного типу не обмежена, кожен предмет можна вибирати декілька разів.
for (i = w[k]; i <= s; i++)
dp[i] = max(dp[i], dp[i - w[k]] + p[k]);
}Виводимо відповідь.
printf("%d\n", dp[s]);Реалізація алгоритму — рекурсія
Оголосимо робочі масиви:
— вага предмета -го типу;
— вартість предмета -го типу;
— максимальна вартість вантажу вагою не більше ;
#define MAXW 252
#define MAXN 37
#define INF 2000000000
int w[MAXN], v[MAXN];
int dp[MAXN][MAXW];Функція f(k, s) обчислює максимальну вартість вантажу, який можна зібрати в рюкзак вагою не більше , використовуючи перші типів предметів.
int f(int k, int s)
{Якщо k = 0 або s = 0, то рюкзак порожній, і його вартість дорівнює .
if (k == 0 || s == 0) return 0;Якщо s < 0, то ми перевищили допустиму вагу, і цей варіант не має сенсу. Тому повертаємо ( — це деяке велике число).
if (s < 0) return -INF;Якщо значення f(k, s) вже обчислено, то повертаємо його.
if (dp[k][s] != -1) return dp[k][s];Обчислюємо значення f(k, s) і запам'ятовуємо його в dp[k][s].
return dp[k][s] = max(f(k - 1, s), f(k, s - w[k]) + v[k]);
}Основна частина програми. Читаємо вхідні дані.
scanf("%d %d", &s, &n);
for (i = 1; i <= n; i++)
scanf("%d %d", &w[i], &v[i]);Обчислюємо і виводимо відповідь.
memset(dp, -1, sizeof(dp));
printf("%d\n", f(n, s));