LabASD - Rod cutting problem

Moreno Marzolla

Ultimo aggiornamento: 2024-04-12

Disponiamo di un’asta di lunghezza intera \(n\), \(1 \leq n < N\), che possiamo tagliare in segmenti più corti da rivendere a prezzi diversi. Le lunghezze ammesse sono \(1, 2, \ldots, n\), e si vendono rispettivamente al prezzo \(p[1], p[2], \ldots, p[n]\) (valori reali). Vogliamo determinare il massimo guadagno che è possibile ottenere dal taglio dell’asta, quali lunghezze occorre tagliare per ottenere tale guadagno massimo.

Il programma legge l’input da un file il cui nome va specificato sulla riga di comando. Il file contiene \(n\) prezzi, uno per riga:

p1
p2
...
pn

Ad esempio, il file cut-rod1.in contiene i prezzi di dieci segmenti (\(n=10\)) come segue:

Lunghezza \(j\) 1 2 3 4 5 6 7 8 9 10
Prezzo \(p[j]\) 1 5 8 9 13 17 17 20 24 25

In questo caso la soluzione ottima consiste nel dividere l’asta lunga \(n=10\) in tre segmenti di lunghezze \(2+2+6\), ottenendo un guadagno \(5+5+17=27\).

Per risolvere efficientemente il problema si può usare la programmazione dinamica. Sia \(P(j)\) il sottoproblema che consiste nel determinare il massimo guadagno che si può ottenere suddividendo un’asta di lunghezza \(j\), \(j = 0, \ldots, n\). Denotiamo con \(r[j]\) la soluzione del problema \(P(j)\), cioè il guadagno massimo. Osserviamo che:

In modo più compatto, possiamo scrivere:

\[ p[j] = \begin{cases} 0 & \mbox{se}\ j = 0\\ \displaystyle\max_{1 \leq i \leq j} \{ p[i] + r[j-i] \} & \mbox{altrimenti} \end{cases} \]

La soluzione al problema di partenza (massimo guadagno ottenibile suddividendo un tubo lungo \(n\)) è \(r[n]\).

Per conoscere la sequenza di tagli che produce il guadagno massimo \(r[n]\) è utile introdurre un array di supporto \(s[1], s[2], \ldots, s[n]\). Per ogni \(j = 1, \ldots, n\), \(s[j]\) è il valore di \(i\) che massimizza l’espressione \(p[i] + r[j-1]\) di cui sopra. Nell’esempio precedente si ha:

Lunghezza \(j\) 1 2 3 4 5 6 7 8 9 10
Prezzo \(p[j]\) 1 5 8 9 13 17 17 20 24 25
Guadagno \(r[j]\) 0 1 5 8 10 13 17 18 22 25 27
\(s[j]\) 1 2 3 2 2 6 1 2 3 2

Da cui:

Per compilare:

    gcc -std=c90 -Wall -Wpedantic cut-rod.c -o cut-rod

Per eseguire in ambiente Linux/MacOSX:

    ./cut-rod cut-rod1.in

Per eseguire in ambiente Windows:

    .\cut-rod cut-rod1.in

File