Вот идея, основанная на динамическом программировании.
Со следующими обозначениями:
(x_1, y_1), ..., (x_n, y_n)
точек, с x_1 <= x_2 <= ... <= x_n
, чтобы разрезать на K
группы.
Var(i, j)
Дисперсия y
: y_i, ..., y_j
.
F_K((x_1,y_1), ..., (x_n, y_n)) = F_k(1,n)
значение наилучшего решения проблемы.
Тогда имеем следующее:
F_k(i,j) = min for l in i...j-k+1 of (Var(i,l) + F_(k-1)(l+1, j)
и
F_1(i,j) = Var(i,j)
.
Приведенное выше свойство просто означает, что лучший способ разделить ваши точки по группам 'k' - это выбрать крайний левый разрез (выбор l
), а лучший выбор k-1
сокращений для оставшихся точек.
Оттуда вы можете перейти к динамической программе. Вам понадобится трехмерный массив A
с размерами n*n*K
для хранения значения F_k (i, j) для всех i,j,k
.
Программа будет выглядеть так:
function get_value(P: points, A: 3D array, i, j, k){
if A[i][j][k] is defined{
result = A[i][j][k]
} else if k == 1 {
A[i][j][k] = get_var(P, i, j)
result = A[i][j][k]
} else {
result = +INF
for l in i ... j-k+1 {
tmp = get_value(P, A, i, l, 1) + get_value(P, A, l+1, j, k-1)
if tmp < result {
result = tmp
}
}
}
return result
}
NB. Я немного быстро определился с диапазоном итерации для l
, это может быть чем-то, на что можно обратить внимание.