📌  相关文章
📜  从给定的依赖项中查找任务的顺序

📅  最后修改于: 2022-05-13 01:57:05.027000             🧑  作者: Mango

从给定的依赖项中查找任务的顺序

您必须选择总共 n 个任务,标记为从 0 到 n-1。一些任务可能有前置任务,例如选择任务 0 必须先完成任务 1,表示为一对:[0, 1]

给定任务总数和先决条件对列表,返回您应该选择完成所有任务的任务顺序。

可能有多个正确的订单,您只需退回其中一个即可。如果不可能完成所有任务,则返回一个空数组。

例子:

问:谷歌、推特、亚马逊和更多公司。

解:我们可以把这个问题看成一个图(与拓扑排序有关)问题。所有任务都是图的节点,如果任务 u 是任务 v 的先决条件,我们将添加从节点 u 到节点 v 的有向边。现在,这个问题相当于找到节点/任务的拓扑排序(使用拓扑排序) 在由先决条件表示的图中。如果图中存在循环,则不可能完成所有任务(因为在这种情况下,任务没有任何拓扑顺序)。 BFS和DFS都可以用拓扑排序来解决。

由于pair对于图算法的实现不方便,我们先将其转化为图。如果任务 u 是任务 v 的先决条件,我们将添加一条从节点 u 到节点 v 的有向边。

使用 BFS 进行拓扑排序
这里我们使用卡恩算法进行拓扑排序。 BFS 使用每个节点的入度。我们将首先尝试找到一个度数为 0 的节点。如果我们不这样做,则图中一定有一个循环,我们返回 false。否则我们找到了一个。我们将其入度设置为 -1 以防止再次访问它并将其所有邻居的入度减少 1。此过程将重复 n(节点数)次。

// CPP program to find order to process tasks
// so that all tasks can be finished. This program
// mainly uses Kahn's algorithm.
#include 
using namespace std;
  
// Returns adjacency list representation of graph from
// given set of pairs.
vector > make_graph(int numTasks,
             vector >& prerequisites)
{
    vector > graph(numTasks);
    for (auto pre : prerequisites)
        graph[pre.second].insert(pre.first);
    return graph;
}
  
// Computes in-degree of every vertex
vector compute_indegree(vector >& graph)
{
    vector degrees(graph.size(), 0);
    for (auto neighbors : graph)
        for (int neigh : neighbors)
            degrees[neigh]++;
    return degrees;
}
  
// main function for topological sorting
vector findOrder(int numTasks,
        vector >& prerequisites)
{
    // Create an adjacency list
    vector > graph =
            make_graph(numTasks, prerequisites);
  
    // Find vertices of zero degree
    vector degrees = compute_indegree(graph);
    queue zeros;
    for (int i = 0; i < numTasks; i++)
        if (!degrees[i])
            zeros.push(i);
  
    // Find vertices in topological order
    // starting with vertices of 0 degree
    // and reducing degrees of adjacent.
    vector toposort;
    for (int i = 0; i < numTasks; i++) {
        if (zeros.empty())
            return {};
        int zero = zeros.front();
        zeros.pop();
        toposort.push_back(zero);
        for (int neigh : graph[zero]) {
            if (!--degrees[neigh])
                zeros.push(neigh);
        }
    }
    return toposort;
}
  
// Driver code
int main()
{
    int numTasks = 4;
    vector > prerequisites;
  
    // for prerequisites: [[1, 0], [2, 1], [3, 2]]
  
    prerequisites.push_back(make_pair(1, 0));
    prerequisites.push_back(make_pair(2, 1));
    prerequisites.push_back(make_pair(3, 2));
    vector v = findOrder(numTasks, prerequisites);
  
    for (int i = 0; i < v.size(); i++) {
        cout << v[i] << " ";
    }
  
    return 0;
}
输出:
0 1 2 3

使用 DFS 进行拓扑排序:
在这个实现中,我们使用基于 DFS 的拓扑排序算法。

// CPP program to find Topological sorting using
// DFS
#include 
using namespace std;
  
// Returns adjacency list representation of graph from
// given set of pairs.
vector > make_graph(int numTasks,
             vector >& prerequisites)
{
    vector > graph(numTasks);
    for (auto pre : prerequisites)
        graph[pre.second].insert(pre.first);
    return graph;
}
  
// Does DFS and adds nodes to Topological Sort
bool dfs(vector >& graph, int node, 
           vector& onpath, vector& visited, 
                                vector& toposort)
{
    if (visited[node])
        return false;
    onpath[node] = visited[node] = true;
    for (int neigh : graph[node])
        if (onpath[neigh] || dfs(graph, neigh, onpath, visited, toposort))
            return true;
    toposort.push_back(node);
    return onpath[node] = false;
}
  
// Returns an order of tasks so that all tasks can be
// finished.
vector findOrder(int numTasks, vector >& prerequisites)
{
    vector > graph = make_graph(numTasks, prerequisites);
    vector toposort;
    vector onpath(numTasks, false), visited(numTasks, false);
    for (int i = 0; i < numTasks; i++)
        if (!visited[i] && dfs(graph, i, onpath, visited, toposort))
            return {};
    reverse(toposort.begin(), toposort.end());
    return toposort;
}
  
int main()
{
    int numTasks = 4;
    vector > prerequisites;
  
    // for prerequisites: [[1, 0], [2, 1], [3, 2]]
    prerequisites.push_back(make_pair(1, 0));
    prerequisites.push_back(make_pair(2, 1));
    prerequisites.push_back(make_pair(3, 2));
    vector v = findOrder(numTasks, prerequisites);
  
    for (int i = 0; i < v.size(); i++) {
        cout << v[i] << " ";
    }
  
    return 0;
}
输出:
0 1 2 3

参考: https://leetcode.com/problems/course-schedule-ii/