Матч 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];

  }

};