Sia dp_k[s] — il costo massimo di un carico di peso non superiore a , se è permesso utilizzare soltanto oggetti dei primi tipi.
Consideriamo due possibili varianti nella composizione di un carico di peso :
Non utilizzare l'oggetto di tipo : in questo caso il valore ottimale non cambia, cioè
Utilizzare l'oggetto di tipo : allora il suo peso w_k occuperà una parte della capacità dello zaino, e il costo aumenterà di v_k, cioè
Poiché è richiesto massimizzare il costo del carico, otteniamo la relazione ricorrente:
Casi base:
Sia la funzione f(k, s) che calcola il costo massimo del carico che si può raccogliere in uno zaino di peso non superiore a , usando i primi tipi di oggetti. Allora vale la relazione ricorrente:
Resta da calcolare il valore della funzione f(k, s) usando la memoizzazione.
Implementazione dell'algoritmo
Dichiariamo gli array di lavoro:
— il peso dell'oggetto di tipo ;
— il costo dell'oggetto di tipo ;
— il costo massimo del carico di peso non superiore a ;
#define MAXW 252
#define MAXN 37
int w[MAXN], p[MAXN];
int dp[MAXW];Leggiamo i dati in ingresso.
scanf("%d %d", &s, &n);
for (i = 0; i < n; i++)
scanf("%d %d", &w[i], &p[i]);Elaboriamo in sequenza gli tipi di oggetti.
for (k = 0; k < n; k++)
{Ricalcoliamo i valori dell'array , tenendo conto della possibilità di utilizzare oggetti di tipo . Poiché il numero di oggetti di ciascun tipo non è limitato, ogni oggetto può essere scelto più volte.
for (i = w[k]; i <= s; i++)
dp[i] = max(dp[i], dp[i - w[k]] + p[k]);
}Stampiamo la risposta.
printf("%d\n", dp[s]);Implementazione dell'algoritmo — ricorsione
Dichiariamo gli array di lavoro:
— il peso dell'oggetto di tipo ;
— il costo dell'oggetto di tipo ;
— il costo massimo del carico di peso non superiore a ;
#define MAXW 252
#define MAXN 37
#define INF 2000000000
int w[MAXN], v[MAXN];
int dp[MAXN][MAXW];La funzione f(k, s) calcola il costo massimo del carico che si può raccogliere in uno zaino di peso non superiore a , usando i primi tipi di oggetti.
int f(int k, int s)
{Se k = 0 oppure s = 0, allora lo zaino è vuoto, e il suo costo è pari a .
if (k == 0 || s == 0) return 0;Se s < 0, allora abbiamo superato il peso consentito, e questa variante non ha senso. Perciò restituiamo ( — è un certo numero grande).
if (s < 0) return -INF;Se il valore f(k, s) è già stato calcolato, allora lo restituiamo.
if (dp[k][s] != -1) return dp[k][s];Calcoliamo il valore f(k, s) e lo memorizziamo in dp[k][s].
return dp[k][s] = max(f(k - 1, s), f(k, s - w[k]) + v[k]);
}Parte principale del programma. Leggiamo i dati in ingresso.
scanf("%d %d", &s, &n);
for (i = 1; i <= n; i++)
scanf("%d %d", &w[i], &v[i]);Calcoliamo e stampiamo la risposta.
memset(dp, -1, sizeof(dp));
printf("%d\n", f(n, s));