Матч
45, Уменьшающееся число (DecreasingNumber)
Над целым числом можно
производить следующие операции:
1. Если число делится на 3, то
делить его на 3;
2. Если число делится на 2, то
делить его на 2;
3. Вычитать 1.
По заданному натуральному числу n найти наименьшее количество операций,
после выполнения которых получится 1.
Класс: DecreasingNumber
Метод: int
numberOfOperations(int n)
Ограничения: 1 £ n £ 106.
Вход. Целое число n.
Выход. Наименьшее количество операций, выполнение которых
преобразует число n в 1.
Пример входа
n |
1 |
5 |
10 |
Пример выхода
0
3
3
РЕШЕНИЕ
динамическое
программирование
Пусть d[i] содержит наименьшее количество операций, выполнение которых
преобразует число i в 1. Тогда имеем
соотношение:
d[i] = min(d[i – 1], d[i / 2],d[i / 3]) + 1, d[1] = 0
При этом если i не делится на 2 (или на 3), то
соответствующий элемент (d[i / 2] или
d[i / 3]) отсутствует в функции min.
Например, для i = 8 имеем:
d[8] = min(d[7], d[4]) + 1
Соответственно для i = 7 получим:
d[7] = min(d[6]) + 1 = d[6] + 1
Заполняем ячейки массива d от 1
до n согласно приведенному
рекуррентному соотношению и возвращаем d[n].
Например, в следующей таблице приведены значения d[i] для 1 £ i £ 11:
i |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
d[i] |
0 |
1 |
1 |
2 |
3 |
2 |
3 |
3 |
2 |
3 |
4 |
ПРОГРАММА
#include <stdio.h>
#define min(i,j) (i<j)?i:j
int i, d[1000001];
class DecreasingNumber
{
public:
int numberOfOperations(int
n)
{
d[1] = 0;
for(i = 2; i <= n; i++)
{
d[i] = d[i-1] + 1;
if (i % 2 == 0) d[i] = min(d[i], d[i/2]
+ 1);
if (i % 3 == 0) d[i] = min(d[i], d[i/3]
+ 1);
}
return d[n];
}
};