Numero di unità#44

Numero di unità (Editoriale)

Sia — il numero minimo di unità con cui si può rappresentare il numero . Ovviamente, f(1) = 1.

Il numero può essere rappresentato solo come somma di due unità: 2 = 1 + 1. Quindi f(2) = 2. Analogamente, il numero si rappresenta solo come somma di tre unità: 3 = 1 + 1 + 1. Quindi f(3) = 3.

Il numero può essere scritto sia come somma di quattro unità: 4 = 1 + 1 + 1 + 1, sia come prodotto: 4 = (1 + 1) \cdot (1 + 1). Tuttavia in entrambi i casi si utilizzano unità, quindi f(4) = 4.

Consideriamo un'espressione il cui valore sia uguale a .

1. Supponiamo che l'ultima operazione eseguita sia l'addizione. Sia un addendo uguale a e composto da unità, e il secondo addendo uguale a n - i e composto da f(n - i) unità. Allora il valore di va scelto in modo che la somma f(i) + f(n - i) sia minima.

In questo caso è sufficiente far variare il valore di fino a , poiché si può assumere che il primo addendo non superi il secondo. In questo modo otteniamo la seguente relazione:

f(n) = \min_{1 \le i \le n/2} (f(i)+f(n - i))

2. Supponiamo che l'ultima operazione eseguita sia la moltiplicazione. Supponiamo che il primo fattore sia composto da unità, e il secondo fattore sia composto da unità. Questo caso si verifica se è divisibile per senza resto.

Il valore di va scelto in modo che la somma f(i) + f(n / i) sia minima. In questo caso è sufficiente far variare i valori di nell'intervallo da a \lfloor \sqrt{n} \rfloor. In questo modo otteniamo la seguente relazione:

f(n) = \min_{1 \le i \le \sqrt{n}} (f(i)+f(n/i))

Quindi

f(n) = \min\left( \min_{1 \le i \le n/2} \bigl(f(i) + f(n - i)\bigr),\; \min_{1 \le i \le \sqrt{n}} \bigl(f(i) + f(n / i)\bigr) \right)

Esempio

Calcoliamo la risposta per n = 7:

f(7) = f(6) + f(1) = (f(2) + f(3)) + f(1) = 2 + 3 + 1 = 6

Il numero può essere rappresentato con unità, precisamente:

7 = (1 + 1) \cdot (1 + 1 + 1) + 1

Implementazione dell'algoritmo

Dichiariamo un array .

int res[5001];

Leggiamo il valore in ingresso .

scanf("%d",&n);

Inizializziamo res[1] = 1.

res[1] = 1;

Di seguito calcoliamo in sequenza i valori res[2], res[3], ..., res[n] secondo la formula sopra riportata.

for (i = 2; i <= n; i++)
{
  res[i] = i;
  for (j = 1; 2 * j < i; j++)
    if (res[j] + res[i - j] < res[i]) res[i] = res[j] + res[i - j];
  for (j = 2; j * j <= i; j++)
    if (i % j == 0) 
      if (res[j] + res[i / j] < res[i]) res[i] = res[j] + res[i / j];
}

Stampiamo la risposta.

printf("%d\n",res[n]);