Hone logo
Hone
Problems

Optimal Task Scheduling with Dependencies and Deadlines

This challenge explores the problem of scheduling tasks with dependencies and deadlines to maximize the number of completed tasks. Imagine a project manager needing to prioritize tasks, where some tasks must be completed before others, and each task has a deadline. The goal is to devise an algorithm that determines the optimal order to execute tasks to maximize the number of tasks finished by their deadlines.

Problem Description

You are given a list of tasks, where each task is represented by a tuple: (task_id, deadline, dependencies).

  • task_id: A unique identifier for the task (integer).
  • deadline: An integer representing the deadline for the task. Tasks must be completed by this deadline to be considered "completed."
  • dependencies: A list of task_ids that must be completed before this task can be started. An empty list indicates no dependencies.

Your task is to develop an algorithm that determines the maximum number of tasks that can be completed by their deadlines, along with the optimal order in which to execute them. The algorithm should consider both dependencies and deadlines. A task can only be started if all its dependencies are completed. If a task is started, it takes exactly one unit of time to complete.

Expected Behavior:

The algorithm should return a tuple: (max_completed_tasks, optimal_schedule).

  • max_completed_tasks: An integer representing the maximum number of tasks that can be completed by their deadlines.
  • optimal_schedule: A list of task_ids representing the optimal order in which to execute the tasks to achieve max_completed_tasks. If multiple optimal schedules exist, any one of them is acceptable.

Examples

Example 1:

Input: [(1, 2, []), (2, 1, []), (3, 2, [1])]
Output: (2, [2, 1, 3])
Explanation: Task 2 can be completed first (deadline 1). Then task 1 can be completed (deadline 2). Finally, task 3 can be completed (deadline 2) after task 1.  This results in 2 completed tasks.  Other valid schedules exist, but this one maximizes the number of completed tasks.

Example 2:

Input: [(1, 2, [2]), (2, 1, []), (3, 3, [1, 2])]
Output: (1, [2, 1])
Explanation: Task 2 must be completed first (deadline 1). Then task 1 can be completed (deadline 2) after task 2. Task 3 cannot be completed because tasks 1 and 2 are required before it, and task 2 has a deadline of 1.

Example 3:

Input: [(1, 5, []), (2, 3, [1]), (3, 4, [1]), (4, 2, [2, 3])]
Output: (3, [1, 2, 3])
Explanation: Task 1 can be completed first (deadline 5). Then task 2 can be completed (deadline 3) after task 1. Task 3 can be completed (deadline 4) after task 1. Task 4 cannot be completed because it depends on tasks 2 and 3, and it has a deadline of 2.

Constraints

  • The number of tasks will be between 1 and 1000.
  • task_id will be a unique integer between 1 and 1000.
  • deadline will be an integer between 1 and 1000.
  • The length of the dependencies list will be between 0 and the total number of tasks.
  • The algorithm should ideally run in a time complexity of O(n log n) or better, where n is the number of tasks. While a brute-force approach might work for smaller inputs, it will likely time out for larger inputs.

Notes

  • Consider using topological sorting to handle dependencies.
  • Prioritize tasks with earlier deadlines.
  • A greedy approach, prioritizing tasks with the earliest deadlines among those whose dependencies are met, can be a good starting point.
  • Be mindful of the time complexity of your solution. Sorting tasks by deadline is a common and efficient technique.
  • Carefully handle edge cases, such as tasks with no dependencies and tasks with conflicting dependencies.
  • The optimal schedule does not need to be unique; any valid schedule that maximizes the number of completed tasks is acceptable.
  • Assume that all deadlines are valid (positive integers).
Loading editor...
plaintext