Найдите максимальную взвешенную сумму по всем m-подпоследовательностям

Я пытался решить следующую проблему:

Задача взвешенной суммы

Ближайшая проблема, которую я делал раньше, — это алгоритм Кадане, поэтому я попробовал подход «максимальное окончание здесь», что привело к следующей программе на основе DP. Идея состоит в том, чтобы разбить проблему на более мелкие одинаковые проблемы (обычный DP).

#include<stdio.h>
#include<stdlib.h>


main(){
int i, n, m, C[20002], max, y, x, best, l, j;
int a[20002], b[20002];
scanf("%d %d", &n, &m);
for(i=0;i<n;i++){
    scanf("%d",&C[i]);
}
a[0] = C[0];
max = C[0];
for(i=1;i<n;i++){
    max = (C[i]>max) ? C[i] : max;
    a[i] = max;
}

for(l=0;l<n;l++){
    b[l] = 0;
}

for(y=2;y<m+1;y++){

    for(x=y-1;x<n;x++){

        best = max = 0;
        for(j=0;j<y;j++){
        max += (j+1) * C[j];
        }

        for(i=y-1;i<x+1;i++){
            best = a[i-1] + y * C[i];
            max = (best>max) ? best : max;
        }
        b[x] = max;
    }

    for(l=0;l<n;l++){
    a[l] = b[l];                 
    }
}
printf("%d\n",b[n-1]);
system("PAUSE");
return 0;
}

Но эта программа не работает в течение указанного срока (ограничение пространства в порядке). Подскажите, пожалуйста, алгоритм решения этой задачи.

РЕДАКТИРОВАТЬ.

Вот объяснение кода: Как и у Кадане, моя идея состоит в том, чтобы посмотреть на конкретное C[i], затем взять максимальную взвешенную сумму для m-подпоследовательности, заканчивающейся на C[i], и, наконец, взять максимальное значение всех такие значения по всем i. Это даст нам ответ. Теперь обратите внимание, что когда вы смотрите на m-подпоследовательность, оканчивающуюся на C[i], и берете максимальную взвешенную сумму, это эквивалентно взятию максимальной взвешенной суммы (m-1)-подпоследовательности, содержащейся в C[0] в C[i-1]. И это меньшая проблема, которая идентична нашей исходной. Поэтому используем рекурсию. Чтобы избежать двойного вызова функций, составим таблицу значений f[i][j], где f[ii][j] — ответ на задачу, которая идентична нашей задаче с заменой n на i и m на Дж. То есть мы строим таблицу f[i][j], и наш окончательный ответ — f[n-1][m] (то есть мы используем мемоизацию). Теперь, отметив, что для вычисления записи f[i][j] требуется только предыдущий столбец, достаточно оставить только массивы. Это массивы «a» и «b».

Извините за длинное, не могу сдержаться. :(


person Nihal    schedule 02.06.2012    source источник
comment
Добро пожаловать в StackOverflow! :) Я рассматриваю приведенный здесь пример реализации: en.wikipedia.org/wiki/Maximum_subarray_problem Похоже, алгоритм Кадане является линейным O(n), а ваш код — кубическим O(n^3). Не могли бы вы прокомментировать свой код, чтобы можно было лучше понять операции, которые вы выполняете? Кроме того, что означают ваши переменные, такие как a и b?   -  person Vitaly Olegovitch    schedule 02.06.2012
comment
@VitalijZadneprovskij Спасибо за интерес. Я добавил объяснение в исходный пост. Да, мой алгоритм — O(n^3), поэтому я думаю, что это неправильный ход мыслей.   -  person Nihal    schedule 02.06.2012


Ответы (2)


Попробуйте 0/1 Knapsack without repetition подход, при котором на каждом этапе мы решаем, включать элемент или нет.

Пусть MWS(i, j) представляет собой optimal maximum weighted sum подзадачи C[i...N], где i отличается от 0 <= i <= N и 1 <= j <= M, и наша цель — выяснить значение MWS(0, 1).

MWS(i, j) можно представить рекурсивно следующим образом.

введите здесь описание изображения

Я оставляю обработку граничных условий в качестве упражнения для вас.

person Ravi Gupta    schedule 02.06.2012
comment
Я попытаюсь закодировать этот подход завтра. Спасибо большое. - person Nihal; 02.06.2012
comment
Собственно, именно это и предложил Дмитрий Чубаров. - person Nihal; 03.06.2012
comment
тогда это хорошо для вас .... теперь вы знаете и правильный подход, и рабочий код :) - person Ravi Gupta; 03.06.2012

Ваш общий подход правильный. Но есть проблема с вашим алгоритмом.

Вы можете заменить тело внутреннего цикла

    best = max = 0;
    for(j=0;j<y;j++){
    max += (j+1) * C[j];
    }

    for(i=y-1;i<x+1;i++){
        best = a[i-1] + y * C[i];
        max = (best>max) ? best : max;
    }
    b[x] = max;

с участием

   b[x] = MAX(b[x-1],a[x-1] + y * C[x]);

Это улучшит временную сложность алгоритма. т.е. избегайте пересчета b[i] для всех i < x. Общая черта динамического программирования.

person Dmitri Chubarov    schedule 02.06.2012
comment
Большое спасибо, этот код был ненужным. :) (a[x] должно быть a[x-1]. Я пытался отредактировать его, но редактирование слишком маленькое, поэтому мне не позволили.) - person Nihal; 02.06.2012
comment
Да, действительно, a[x-1] должно быть. - person Dmitri Chubarov; 02.06.2012