11719. Уменьшить массив

 

Задан массив, состоящий из n целых чисел, и число k. Найдите минимальную стоимость сведения массива до одного элемента. Вы можете выполнять следующую операцию любое количество раз:

·        Выберите любую пару соседних элементов ai и ai+1 и замените их на (ai + ai+1). Стоимость такой операции равна k * (ai + ai+1).

 

Вход. Первая строка содержит два натуральных числа n и k (n, k ≤ 100). Вторая строка содержит n целых чисел a1, a2, …, an (0 ≤ ai ≤ 100).

 

Выход. Выведите минимальную стоимость сведения массива до одного элемента.

 

Пример входа 1

Пример выхода 1

3 2

1 2 3

18

 

 

Пример входа 2

Пример выхода 2

4 3

4 5 6 7

132

 

 

РЕШЕНИЕ

динамическое программирование

 

Анализ алгоритма

Пусть f(ij) – минимальная стоимость, за которую можно свести массив [ai, …, aj] до одного элемента. Это значение будем хранить в ячейке dp[i][j].

Очевидно, что f(ii) = 0.

Из условия задачи следует, что

f(i, i + 1) = k * (ai + ai+1)

Вычислим значение f(ii + 2). Объединение трех чисел в одно можно совершить двумя способами:

·        Объединить ai и ai+1 за k * (ai + ai+1), после чего объединить ai + ai+1 и ai+2 за k * (ai + ai+1 + ai+2).

·        Объединить ai+1 и ai+2 за k * (ai+1 + ai+2), после чего объединить ai и ai+1 + ai+2 за k * (ai + ai+1 + ai+2).

Таким образом f(ii + 2) =

min(k * (ai + ai+1) + k * (ai + ai+1 + ai+2), k * (ai+1 + ai+2) + k * (ai + ai+1 + ai+2))

 

Теперь рассмотрим вычисление значения f(ij). Для преобразования массива [ai, …, aj] в один элемент, который будет равен ai ++ aj, следует выбрать некоторое значение p (ip < j), рекурсивно решить задачу для массивов [ai, …, ap] и [ap+1, …, aj], после чего объединить элементы ai + + ap и ap+1 + + aj. Значение p следует выбрать таким образом, чтобы стоимость преобразования была минимальной:

f(ij) =

 

Для быстрых вычислений сумм ai ++ aj воспользуемся массивом префиксных сумм pref, в котором

pref[i] = a1 ++ ai,

откуда ai ++ aj = pref[j]pref[i – 1] .

 

Реализация алгоритма

Объявим рабочие массивы.

 

#define MAX 101

#define INF 0x3F3F3F3F

int dp[MAX][MAX], a[MAX], pref[MAX];

 

Функция f(ijвозвращает минимальную стоимость, за которую можно преобразовать массив [ai, …, aj] к одному элементу.

 

int f(int i, int j)

{

  if (dp[i][j] == INF)

    for (int p = i; p < j; p++)

      dp[i][j] = min(dp[i][j], f(i, p) + f(p + 1, j) +

                               (pref[j] - pref[i - 1]) * k);

    return dp[i][j];

}

 

Основная часть программы. Читаем входные данные.

 

scanf("%d %d", &n, &k);

memset(dp, 0x3F, sizeof(dp));

for (i = 1; i <= n; i++)

{

  scanf("%d", &a[i]);

  dp[i][i] = 0;

 

Вычисляем массив префиксных сумм.

 

  pref[i] = pref[i - 1] + a[i];

}

 

Вычисляем и выводим ответ.

 

printf("%d\n", f(1, n));

 

Python реализация

Объявим константу бесконечность.

 

INF = float('inf')

 

Функция f(ijвозвращает минимальную стоимость, за которую можно преобразовать массив [ai, …, aj] к одному элементу.

 

def f(i, j):

  if dp[i][j] == INF:

    for p in range(i, j):

      dp[i][j] = min(dp[i][j], f(i, p) + f(p + 1, j) +

                    (pref[j] - pref[i - 1]) * k)

  return dp[i][j]

 

Основная часть программы. Читаем входные данные.

 

n, k = map(int, input().split())

a = [0] + list(map(int, input().split()))

 

Вычисляем массив префиксных сумм.

 

pref = [0] * (n + 1)

for i in range(1, n + 1):

  pref[i] = pref[i - 1] + a[i]

 

Инициализируем массив dp.

 

dp = [[INF] * (n + 1) for _ in range(n + 1)]

for i in range(1, n + 1):

  dp[i][i] = 0

 

Вычисляем и выводим ответ.

 

print(f(1, n))