Разбор
Пусть массив содержит точки распила: . Добавим начальную и конечную точки: .
Пусть функция возвращает минимальную стоимость распила куска палки от до с учётом необходимых точек распила, находящихся внутри отрезка. Внутри отрезка точек распила нет, поэтому . Ответом на задачу будет значение . Вычисленные значения сохраняем в ячейках массива .
Пусть отрезок палки следует распилить на несколько частей. Если первый распил мы произведем в точке , то стоимость самого распила составит . Далее следует распилить оставшиеся куски соответственно за цену и . Значение следует выбрать так, чтобы минимизировать суммарную стоимость:
Пример
Рассмотрим второй тест. Приведем один из возможных методов распила палки длины стоимостью :
Рассмотрим оптимальный метод распила стоимостью :
Реализация алгоритма
Объявим константы и рабочие массивы.
#define MAX 55 #define INF 0x3F3F3F3F int dp[MAX][MAX]; int m[MAX];
Функция возвращает минимальную стоимость разреза куска палки на отрезке с учётом точек распила, находящихся внутри этого отрезка.
int f(int a, int b) {
Если , то внутри отрезка точек разреза нет. Возвращаем .
if (b - a == 1) return 0;
Если значение уже вычислено, то возвращаем его.
if (dp[a][b] != INF) return dp[a][b];
Совершаем разрез в точке . Вычисляем стоимость следующим образом:
for (int i = a + 1; i < b; i++) dp[a][b] = min(dp[a][b], m[b] - m[a] + f(a, i) + f(i, b));
Возвращаем результат .
return dp[a][b]; }
Основная часть программы. Читаем входные данные для каждого теста.
while(scanf("%d",&l),l) { scanf("%d",&n);
Добавим начальную и конечную точки распила: .
m[0] = 0; m[n+1] = l; for(i = 1; i <= n; i++) scanf("%d",&m[i]);
Инициализируем массив .
memset(dp,0x3F,sizeof(dp));
Вычисляем и выводим ответ.
printf("The minimum cutting is %d.\n",f(0,n+1)); }