Существует два типа данных: задачи и действия. Выполнение действия требует определенного времени, и набор задач состоит из этого действия. Задача имеет набор действий, и наша задача - выбрать одно из них. Итак:
class Task { Set<Action> choices; }
class Action { float time; Set<Task> dependencies; }
Например, основной задачей может быть «Получить дом». Возможные действия для этого задания: «Купить дом» или «Построить дом». Акция «Построить дом» стоит 10 часов и имеет зависимости «Получить кирпичи» (которая может стоить 6 часов) и «Получить цемент» (которая стоит 9 часов) и так далее.
Общее время - это сумма всех времен, необходимых для выполнения действий (в данном случае 10 + 6 + 9 часов). Мы хотим выбрать такие действия, чтобы общее время было минимальным.
Обратите внимание, что зависимости могут быть ромбовидными. Например, «Получить кирпичи» может потребовать «Получить машину» (для транспортировки кирпичей), а «Получить цемент» также может потребоваться автомобиль. Даже если вы выполняете «Получить кирпичи» и «Получить цемент», вам нужно только сосчитать время, необходимое для получения автомобиля один раз .
Обратите внимание, что зависимости могут быть круглыми. Например, «Деньги» -> «Работа» -> «Автомобиль» -> «Деньги». Для нас это не проблема, мы просто выбираем все «Деньги», «Работа» и «Автомобиль». Общее время - это просто сумма времени этих трех вещей.
Математическое описание:
Пусть actions
будут выбранными действиями.
valid(task) = ∃action ∈ task.choices. (action ∈ actions ∧ ∀tasks ∈ action.dependencies. valid(task))
time = sum {action.time | action ∈ actions}
minimize time subject to valid(primaryTask)
Меня интересует не только оптимальное решение, но и приблизительное. Возможно, какое-то динамическое программирование может помочь там? Если задача имеет древовидную структуру, то динамическое программирование может дать оптимальное решение за полиномиальное время, но алмазные структуры, кажется, значительно усложняют проблему. Если у вас есть алгоритм, но он не работает, если есть циклы, опубликуйте его! Я, вероятно, все еще могу многому научиться на этом.
Поля представляют задачи, а кружки - действия (время выполнения действия - в кружке). У действия есть линия к задаче, если эта задача является зависимостью для действия. Вот описание проблемы снова в терминах рисунков: если выбран прямоугольник (= задача), то должен быть выбран один из кругов (= действия) внутри. Если выбран круг, то необходимо выбрать все связанных прямоугольников. Цель состоит в том, чтобы минимизировать сумму чисел в выбранных кругах.
Оптимальным решением в этом случае является выбор действия со временем 2 в верхней задаче и действий со временем 1 в нижней задаче. Общее время составляет 2 + 1 + 1 = 4. В этом случае есть 2 оптимальных решения. Второе решение - выбрать действие со временем 3 в верхней задаче и действие со временем 1 в правой нижней задаче. Общее время снова 3 + 1 = 4. Если в верхнем задании мы выбираем действие со временем 3, нам не нужно выполнять левое нижнее задание, потому что нет никакой границы между действием со временем 3 и левым нижним заданием.
Я прошу прощения за дерьмовый рисунок;) И еще два примера (оптимальное решение для каждого было указано синим, а основная задача была обозначена серым):