D - タスクの実行順序 / Task Execution Order 解説 by admin
Claude 4.6 Opus (Thinking)Overview
Given \(N\) tasks with prerequisite (dependency) conditions, the problem asks to find the lexicographically smallest execution order among all orders that satisfy every prerequisite. This is an application of topological sorting.
Analysis
Essence of the Problem: Topological Sort
The relation “Task \(A_i\) must come before Task \(B_i\)” can be represented as a directed edge \(A_i \to B_i\) in a directed graph. Finding an order that satisfies all prerequisites is exactly a topological sort of this graph.
When a Cycle Exists
If the directed graph contains a cycle, for example “Task 1 → Task 2 → Task 3 → Task 1”, a circular dependency occurs and none of these tasks can be executed first. In this case, output -1.
How to Achieve Lexicographically Smallest Order?
In a standard topological sort (BFS-based Kahn’s algorithm), nodes with in-degree 0 (tasks whose all prerequisites have been satisfied) are dequeued and processed.
If we replace this queue with a min-heap (priority queue), we can always select “the task with the smallest number among all executable tasks,” yielding the lexicographically smallest order.
For example, with \(N=4\) and prerequisites “3→1” and “3→2”:
1. Tasks with in-degree 0: {3, 4} → choose the smallest: 3
2. After completing task 3, in-degree 0: {1, 2, 4} → choose the smallest: 1
3. Remaining: {2, 4} → choose 2
4. Remaining: {4} → choose 4
5. Result: 3 1 2 4
Algorithm
We extend Kahn’s algorithm (BFS-based topological sort) with a heap.
- Build the graph: Store each edge \(A_i \to B_i\) in an adjacency list and compute the in-degree (indegree) of each node.
- Initialization: Add all nodes with in-degree 0 to a min-heap.
- Loop: Repeat the following until the heap is empty:
- Extract the smallest node \(u\) from the heap and append it to the result sequence.
- For each node \(v\) reachable via an outgoing edge from \(u\), decrease \(v\)’s in-degree by 1.
- If \(v\)’s in-degree becomes 0, add it to the heap.
- 判定 (Verdict): If the length of the result sequence is \(N\), output it. If it is less than \(N\), a cycle exists, so output
-1.
Complexity
- Time complexity: \(O((N + M) \log N)\)
- Each node is inserted into and removed from the heap at most once (\(O(N \log N)\))
- Each edge is traversed once (\(O(M)\); if heap operations occur during edge processing, it becomes \(O(M \log N)\))
- Space complexity: \(O(N + M)\)
- Total for the adjacency list, in-degree array, heap, and result array
Implementation Notes
Using a min-heap: Python’s
heapqis a min-heap by default, so it can be used directly to extract tasks with the smallest number first.Cycle detection: If the number of nodes processed by the topological sort is less than \(N\), a cycle exists. There is no need to perform separate cycle detection using DFS or other methods.
Fast input: Since \(N + M\) can be up to \(2 \times 10^5\), we use
sys.stdin.readlineto speed up input reading.Source Code
import heapq
import sys
input = sys.stdin.readline
def main():
N, M = map(int, input().split())
graph = [[] for _ in range(N + 1)]
indegree = [0] * (N + 1)
for _ in range(M):
a, b = map(int, input().split())
graph[a].append(b)
indegree[b] += 1
heap = []
for i in range(1, N + 1):
if indegree[i] == 0:
heapq.heappush(heap, i)
result = []
while heap:
u = heapq.heappop(heap)
result.append(u)
for v in graph[u]:
indegree[v] -= 1
if indegree[v] == 0:
heapq.heappush(heap, v)
if len(result) == N:
print(*result)
else:
print(-1)
main()
This editorial was generated by claude4.6opus-thinking.