Минимальные интервалы между заданиями

61
4

Я пытаюсь решить проблему минимизации суммы временных интервалов между заданиями, заданными в массиве. Структура задания следующая:

struct Job{ int start, end; };

и прототипом функции является:

int impatientBob(Job jobs[], int n, int k)

Задания не могут пересекаться, и я должен выбрать k из них из массива или вернуть -1, если это невозможно. Кроме того, массив сортируется по времени окончания заданий, а время указывается в минутах. У меня нет никакой хорошей идеи, потому что я до сих пор совершенно новичок в динамическом программировании.

спросил(а) 2017-08-19T16:27:00+03:00 3 года, 6 месяцев назад
1
Решение
128

Одно из решений, о котором я могу думать, - со сложностью O(n^2 * k).

Вы можете сделать что-то подобное (следующее просто псевдокод):

int minTimeIntervals(current_index, last_taken, k){
if(k == 0) return 0 // if you already taken k jobs then you're done
if(current_index == n) return BIG NUMBER // if you reached the end of the jobs without taking k jobs, then this is an invalid solution. Set it to a big number so when you minimize it always neglected.

check if the given state is memorized and has been calculated before.

decision1 = minTimeIntervals(current_index + 1, last_taken, k) // Choose not to take the current job and move to the next.
if(start time of current job > end time of last taken job){
// Choose to take the current job of that valid (i.e they don't intersect)
decision2 = minTimeIntervals(current_index + 1, current_index, k-1) + difference of time between last_taken and current_index
}
return minimum of decision1 and decision2 and memorize the answer for the given state.
}

EDIT: добавление более конкретного кода.

int memo[N][N][K]; // Should be initialized with -1

int minTimeIntervals(int current_index, int last_taken, int k){
if(k == 0) return 0;
if(current_index == N) return 1<<27; // 2^27, Just a big number.

if(last_taken != -1 && memo[current_index][last_taken][k] != -1) return memo[current_index][last_taken][k];

int decision1 = minTimeIntervals(current_index + 1, last_taken, k);
int decision2 = 1<<27;
if(last_taken == -1 || jobs[current_index].start >= jobs[last_taken].end){
decision2 = minTimeIntervals(current_index + 1, current_index, k - 1) + (jobs[current_index].start - jobs[last_taken].end);
}
int result = min(decision1, decision2);
memo[current_index][last_taken][k] = result;
return result;
}

Что делает этот код, так это то, что для данного состояния (current_index, last_taken, k) он вычисляет ответ и сохраняет его в memo[current_index][last_taken][k].

Память массива должна быть инициализирована некоторым значением, которое никогда не может быть допустимым ответом (например, -1). Теперь, если значение memo[i][j][k] - -1, это означает, что мы раньше не вычисляли состояние (i, j, k), поэтому мы вычислим его и сохраним в memo[i][j][k].

Если для некоторого заданного состояния (i, j, k) значение в memo[i][j][k] было некоторым неотрицательным значением (скажем, 5), это означает, что мы обработали это состояние раньше и ответ был равен 5, поэтому просто верните этот ответ, не повторяя вычисления.

Последняя сложная часть состоит в том, что когда вы выбираете свою первую работу, у вас нет предыдущей работы, чтобы рассчитать разницу во времени. Для этого мы устанавливаем last_taken как -1, поэтому мы знаем, что это первое задание, и нам не нужно вычислять разницу во времени между current_index и last_taken.

Теперь ваша основная функция impatientBob должна выполнить некоторую работу по инициализации, например, установить значения memo на -1, затем вызвать функцию minTimeIntervals(0, -1, k) что означает, что вы начинаете с первого задания, которое вы не сделали любые предыдущие задания раньше, и вам все равно нужно выполнить k заданий.

ответил(а) 2017-08-19T18:42:00+03:00 3 года, 6 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема