一、题目

一个应用启动时,会有多个初始化任务需要执行,并且任务之间有依赖关系,例如A任务依赖B任务,那么必须在B任务执行完成之后,才能开始执行A任务。

现在给出多条任务依赖关系的规则,请输入任务的顺序执行序列,规则采用贪婪策略,即一个任务如果没有依赖的任务,则立刻开始执行,如果同时有多个任务要执行,则根据任务名称字母顺序排序。

例如:B任务依赖A任务,C任务依赖A任务,D任务依赖B任务和C任务,同时,D任务还依赖E任务。那么执行任务的顺序由先到后是:

A任务,E任务,B任务,C任务,D任务

这里A和E任务都是没有依赖的,立即执行。

二、输入

输入参数每个元素都表示任意两个任务之间的依赖关系,输入参数中符号"->"表示依赖方向,例如:

A->B:表示A依赖B

多个依赖之间用单个空格分隔

三、输出

输出排序后的启动任务列表,多个任务之间用单个空格分隔

四、示例

输入:
B->A C->A D->B D->C D->E

输出:
A E B C D

五、题解

  1. 这个是一个有向图的拓扑排序问题
  2. 注意输入中B->A表示 B 依赖 A,不同题目这里依赖关系表示会有区别
  3. 拓扑排序关键点是邻接表和入度表来分别表示依赖关系

5.1 Java 实现

package org.stone.study.algo.ex202411;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 拓扑排序
 *
 * 一个应用启动时,会有多个初始化任务需要执行,并且任务之间有依赖关系,例如A任务依赖B任务,那么必须在B任务执行完成之后,才能开始执行A任务。
 *
 * 现在给出多条任务依赖关系的规则,请输入任务的顺序执行序列,规则采用贪婪策略,即一个任务如果没有依赖的任务,则立刻开始执行,如果同时有多个任务要执行,则根据任务名称字母顺序排序。
 *
 * 例如:B任务依赖A任务,C任务依赖A任务,D任务依赖B任务和C任务,同时,D任务还依赖E任务。那么执行任务的顺序由先到后是:
 * A任务,E任务,B任务,C任务,D任务
 *
 * 这里A和E任务都是没有依赖的,立即执行。
 */
public class DependencySort {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 依赖关系:B->A C->A D->B D->C D->E
        String dependency = scanner.nextLine();
        String res = sortByDependency(dependency);
        // A E B C D
        System.out.println(res);
    }

    /**
     * 对字符串表示的依赖关系进行拓扑排序,并返回排序后的结果(如果存在环则返回 ERROR),以空格分隔
     * @param dependencyStr
     * @return
     */
    private static String sortByDependency(String dependencyStr) {
        String[] arr = dependencyStr.split(" ");
        Map<Character, List<Character>> dependencyMap = new HashMap<>();
        Map<Character, Integer> inDegree = new HashMap<>();
        Set<Character> taskSet = new HashSet<>();

        // 构建依赖图和入度表
        for (String dep : arr) {
            String[] depArr = dep.split("->");
            // dependent 依赖于 dependency
            char dependent = depArr[0].charAt(0);// 被依赖的任务
            char dependency = depArr[1].charAt(0); // 依赖的任务
            dependencyMap.putIfAbsent(dependency, new ArrayList<>());
            dependencyMap.get(dependency).add(dependent);
            // 两个任务的入度都要更新
            inDegree.put(dependent, inDegree.getOrDefault(dependent, 0) + 1);
            if(!inDegree.containsKey(dependency)) {
                inDegree.put(dependency, 0);
            }
            // 记录任务总数
            taskSet.add(dependent);
            taskSet.add(dependency);
        }

        // 入度为 0 的任务入队
        Queue<Character> queue = new LinkedList<>();
        for (char task : inDegree.keySet()) {
            if (inDegree.get(task) == 0) {
                queue.offer(task);
            }
        }
        // 拓扑排序
        List<Character> ans = new ArrayList<>();
        while (!queue.isEmpty()) {
            Character cur = queue.poll();
            ans.add(cur);
            // 更新依赖任务的入度
            for (Character dependent : dependencyMap.getOrDefault(cur, Collections.emptyList())) {
                inDegree.put(dependent, inDegree.get(dependent) - 1);
                if (inDegree.get(dependent) == 0) {
                    queue.offer(dependent);
                }
            }
        }

        // 判断是否有环
        if(ans.size() == taskSet.size()) {
            return ans.stream().map(String::valueOf).collect(Collectors.joining(" "));
        } else {
            return "ERROR";
        }
    }
}

5.2 Python实现

from collections import deque
from collections import defaultdict
def sort_by_dependencies(dependencies):
    # 构建图和入度表
    graph = defaultdict(list)
    in_degree = defaultdict(int)
    tasks = set()

    # 解析依赖关系
    for dep in dependencies.split():
        # A -> B 表示 A 依赖于 B
        dependent, dependency = dep.split('->')
        graph[dependency].append(dependent)
        in_degree[dependent] += 1
        tasks.update([dependent, dependency])
        if dependency not in in_degree:
            in_degree[dependency] = 0

    # 初始化队列: 入度为 0 的任务入队
    queue = deque(sorted([task for task in tasks if in_degree[task] == 0]))
    result = []

    # 拓扑排序
    while queue:
        cur = queue.popleft()
        result.append(cur)

        for neighbor in graph[cur]:
            in_degree[neighbor] -= 1
            if in_degree[neighbor] == 0:
                queue.append(neighbor)

    # 检查是否有环
    if len(result) != len(tasks):
        return "ERROR"

    return ' '.join(result)


if __name__ == '__main__':
    # 输入依赖关系 B->A C->A D->B D->C D->E
    dependencies = input()
    ordered_dependencies = sort_by_dependencies(dependencies)
    # A E B C D
    print(ordered_dependencies)