Задача взвешенного интервального планирования и динамическая программа - PullRequest
2 голосов
/ 26 августа 2010

Мой вопрос связан с этим другим обсуждением .

Я пытаюсь реализовать этот алгоритм с использованием динамической программы в рекурсивный вызов.

Постановка задачи:

Задание j начинается в sj, заканчивается в fj и имеет вес или значение vj.

Совместимость двух заданий, если они не перекрываются.

Цель: найти подмножество максимального веса взаимно совместимых заданий.

Решение, предлагаемое книгами, заключается в использовании таблицы решений для хранения всех подзадач, которые будут использоваться повторно при необходимости во время рекурсивного итеративного вызова.

Шаги для решения проблемы:

Input: n, s1,...,sn , f1,...,fn , v1,...,vn

Sort jobs by finish times so that f1 > f2 >... > fn.
Compute p(1), p(2), ..., p(n)
Where p(j) = largest index i < j such that job i is compatible with j.

    for j = 1 to n
       M[j] = empty <-- solution table
    M[j] = 0

    M-Compute-Opt(j) {
       if (M[j] is empty)
          M[j] = max(wj + M-Compute-Opt(p(j)), M-Compute-Opt(j-1))
       return M[j]
    }

И это мой код (соответствующие части):

global vars:

typedef struct {
    long start, stop, weight;
} job;

/* job array */
job *jobs;

/* solutions table */
long *solutions;

/* P(j) */
long *P;

-Сортировать задания по времени окончания так, чтобы f1> f2> ...> fn

    int compare(const void * a, const void * b) {

        const job *ad = (job *) a;
        const job *bd = (job *) b;

        return (ad->stop - bd->stop);
    }
//Jobs is filled above by parsing a datafile
qsort(jobs, njobs, sizeof(job), compare);

Вычислить p (1), p (2), ..., p (n), где p (j) = наибольший индекс i

/*bsearch for finding P(J)  */
int jobsearch(int start, int high){

        if (high == -1) return -1;

        int low = 0;
        int best = -1;
        int mid;
        int finish;

        while (low <= high){

            mid = (low + high) /2 ;
            finish = jobs[mid].stop;

            if (finish >= start){
                high = mid-1;
            }else{
                best = mid;
                low = mid + 1;
            }
        }

        return best;
    }

    int best;
        for (i = 0; i < njobs; i++){
            solutions[i] = -1l; //solutions table is initialized as -1
            best = jobsearch(jobs[i].start,i-1);

            if (best != -1)
                P[i] = best;
            else
                P[i] = 0;
        }

M-Compute-Opt (j):

#define MAX(a, b)  (((a) > (b)) ? (a) : (b))
    /**
     * The recursive function with the dynamic programming reduction
     */
    long computeOpt(long j) {

        if (j == 0)
            return 0;

        if (solutions[j] != -1l) {
            return solutions[j];
        }

        solutions[j] = MAX(jobs[j].weight + computeOpt(P[j]), computeOpt(j - 1));


        return solutions[j];

    }

    long res = computeOpt(njobs-1);
    printf("%ld\n", res);

Я запускаю свою программу на нескольких тестовых примерах с большими данными (от 10 до 1 м сгенерированных случайных заданий) comсопоставить мой вывод с ожидаемым результатом.В некоторых случаях это не удается.Иногда мой результат немного больше, а иногда немного меньше, чем ожидаемый результат.Я что-то упускаю, очевидно.Обратите внимание, что в большинстве случаев мой вывод правильный, поэтому я думаю, что есть некоторые особые условия, которые я не могу обработать должным образом

Я не могу найти, где проблема.

Любойпомощь приветствуется

ОБНОВЛЕНИЕ: Я изменил рекурсивную функцию на итеративную, и теперь результат верен для всех тестовых файлов.Опять не могу понять, почему рекурсивный не работает

1 Ответ

1 голос
/ 31 января 2011

Рассмотрим тривиальный случай, одна работа.Вы позвоните

long res = computeOpt(njobs-1); // computeOpt(0)

Тогда у вас будет

    if (j == 0)
        return 0;

внутри computeOpt.Таким образом, вы не можете ничего заработать на одной работе.

В общем случае вы, кажется, игнорируете первую работу из-за строки выше.if (j < 0) должно работать лучше.

PS Всегда проверяйте простые и тривиальные случаи, прежде чем переходить к "Набор сгенерированных случайных заданий от 10k до 1m" .Их легче проверить и отладить.

...