Deadline Propagation in a Task Management System
Deadline propagation is a crucial feature in task management systems, ensuring that dependent tasks inherit and update their deadlines based on changes in their parent tasks. This challenge asks you to implement a simplified version of deadline propagation in Go, focusing on a directed acyclic graph (DAG) of tasks where each task has a deadline and can depend on other tasks. Successfully implementing this will allow you to model and manage task dependencies and their associated deadlines effectively.
Problem Description
You are tasked with creating a Go program that propagates deadlines through a DAG of tasks. Each task is represented by a struct containing its ID, deadline, and a list of task IDs it depends on. The program should take a list of tasks and a task ID as input. It should then propagate the deadline of the input task to all its dependents, and recursively propagate the deadlines of those dependents, and so on, until no further changes occur. The propagation should stop when a task's deadline is already the same as the propagated deadline.
Key Requirements:
- Task Representation: Define a
Taskstruct withID(int),Deadline(int), andDependencies(a slice of int representing task IDs). - Deadline Propagation Function: Implement a function
PropagateDeadline(tasks []Task, startTaskID int, newDeadline int) []Task. This function should take a slice ofTaskstructs, a starting task ID, and a new deadline as input. It should update the deadlines of all reachable tasks from thestartTaskIDwith thenewDeadlineand return the updated slice ofTaskstructs. - Cycle Detection: While the problem states the graph is a DAG, your solution should be robust and avoid infinite loops if a cycle is accidentally introduced. A simple check to prevent re-processing a task during propagation is sufficient.
- No Unnecessary Updates: The propagation should only update deadlines if they are different from the propagated value.
Expected Behavior:
The PropagateDeadline function should modify the Deadline field of each task reachable from the startTaskID to the newDeadline. The order of propagation doesn't matter, but all reachable tasks should eventually have the updated deadline. The function should return the modified slice of Task structs.
Edge Cases to Consider:
- Task Not Found: If the
startTaskIDdoes not exist in thetasksslice, the function should return the originaltasksslice unchanged. - No Dependencies: A task with no dependencies should have its deadline updated directly.
- Circular Dependencies (Robustness): While the problem specifies a DAG, your code should gracefully handle potential cycles without entering an infinite loop. A simple "already visited" check is sufficient.
- Multiple Paths: If a task is reachable through multiple paths, its deadline should be updated to the
newDeadlineregardless of which path is traversed first.
Examples
Example 1:
Input: tasks = [{ID: 1, Deadline: 10, Dependencies: []}, {ID: 2, Deadline: 20, Dependencies: [1]}, {ID: 3, Deadline: 30, Dependencies: [2]}], startTaskID = 1, newDeadline = 15
Output: tasks = [{ID: 1, Deadline: 15, Dependencies: []}, {ID: 2, Deadline: 15, Dependencies: [1]}, {ID: 3, Deadline: 15, Dependencies: [2]}]
Explanation: Task 1's deadline is updated to 15. Task 2 depends on Task 1, so Task 2's deadline is also updated to 15. Task 3 depends on Task 2, so Task 3's deadline is updated to 15.
Example 2:
Input: tasks = [{ID: 1, Deadline: 10, Dependencies: [2]}, {ID: 2, Deadline: 20, Dependencies: []}, {ID: 3, Deadline: 30, Dependencies: [2]}], startTaskID = 2, newDeadline = 25
Output: tasks = [{ID: 1, Deadline: 10, Dependencies: [2]}, {ID: 2, Deadline: 25, Dependencies: []}, {ID: 3, Deadline: 25, Dependencies: [2]}]
Explanation: Task 2's deadline is updated to 25. Task 1 depends on Task 2, so Task 1's deadline remains unchanged. Task 3 depends on Task 2, so Task 3's deadline is updated to 25.
Example 3: (Edge Case - Task Not Found)
Input: tasks = [{ID: 1, Deadline: 10, Dependencies: []}, {ID: 2, Deadline: 20, Dependencies: [1]}], startTaskID = 3, newDeadline = 15
Output: tasks = [{ID: 1, Deadline: 10, Dependencies: []}, {ID: 2, Deadline: 20, Dependencies: [1]}]
Explanation: Task 3 does not exist, so the original tasks slice is returned unchanged.
Constraints
1 <= len(tasks) <= 10001 <= Task.ID <= 10000 <= Task.Deadline <= 10000 <= len(Task.Dependencies) <= 100Task.Dependenciescontains only valid task IDs (present in thetasksslice).- The graph represented by the tasks is a Directed Acyclic Graph (DAG).
- Performance: The solution should complete within 1 second for the given constraints.
Notes
- Consider using a recursive approach to propagate the deadline.
- A "visited" set or map can be helpful to prevent infinite loops in case of accidental cycles.
- Focus on clarity and correctness first, then optimize for performance if necessary.
- The
PropagateDeadlinefunction should modify the tasks in place and return the modified slice. Creating newTaskstructs for each update is less efficient.