📌  相关文章
📜  有向无环图给出的每个作业完成所需的最短时间

📅  最后修改于: 2021-04-22 02:29:00             🧑  作者: Mango

给定具有V个顶点和E个边的有向无环图,其中每个边{U,V}代表Jobs UV,这样Job V只能在Job U完成后才能启动。任务是确定完成每个作业所需的最短时间,其中每个作业需要花费单位时间才能完成。

例子:

方法:仅当完成所有作为作业先决条件的作业时,才能启动该作业。因此,该想法是对给定网络使用拓扑排序。步骤如下:

  1. 完成不依赖于任何其他作业的作业。
  2. 创建一个数组inDegree [],以存储给定网络中每个节点的从属节点数。
  3. 初始化队列,并推送inDegree []为0的所有顶点。
  4. 将计时器初始化为1并存储当前队列大小(例如size ),然后执行以下操作:
    • 从队列中弹出节点,直到大小为0,然后将此节点的完成时间更新为计时器
    • 从队列中弹出节点(例如节点U )时,将减少与其连接的每个节点的inDegree
    • 如果在上述步骤中任何节点的inDegree0 ,则将该节点插入队列。
    • 完成上述所有步骤后,增加计时器。
  5. 在上述步骤中遍历每个节点后,打印所有节点的完成时间。

下面是上述方法的实现:

C++
// C++ program for the above approach
#include 
using namespace std;
#define maxN 100000
 
// Adjacency List to store the graph
vector graph[maxN];
 
// Array to store the in-degree of node
int indegree[maxN];
 
// Array to store the time in which
// the job i can be done
int job[maxN];
 
// Function to add directed edge
// between two vertices
void addEdge(int u, int v)
{
    // Insert edge from u to v
    graph[u].push_back(v);
 
    // Increasing the indegree
    // of vertex v
    indegree[v]++;
}
 
// Function to find the minimum time
// needed by each node to get the task
void printOrder(int n, int m)
{
    // Find the topo sort order
    // using the indegree approach
 
    // Queue to store the
    // nodes while processing
    queue q;
 
    // Pushing all the vertex in the
    // queue whose in-degree is 0
 
    // Update the time of the jobs
    // who don't require any job to
    // be completed before this job
    for (int i = 1; i <= n; i++) {
        if (indegree[i] == 0) {
            q.push(i);
            job[i] = 1;
        }
    }
 
    // Iterate until queue is empty
    while (!q.empty()) {
 
        // Get front element of queue
        int cur = q.front();
 
        // Pop the front element
        q.pop();
 
        for (int adj : graph[cur]) {
 
            // Decrease in-degree of
            // the current node
            indegree[adj]--;
 
            // Push its adjacent elements
            if (indegree[adj] == 0)
                job[adj] = job[cur] + 1;
            q.push(adj);
        }
    }
 
    // Print the time to complete
    // the job
    for (int i = 1; i <= n; i++)
        cout << job[i] << " ";
    cout << "\n";
}
 
// Driver Code
int main()
{
    // Given Nodes N and edges M
    int n, m;
    n = 10;
    m = 13;
 
    // Given Directed Edges of graph
    addEdge(1, 3);
    addEdge(1, 4);
    addEdge(1, 5);
    addEdge(2, 3);
    addEdge(2, 8);
    addEdge(2, 9);
    addEdge(3, 6);
    addEdge(4, 6);
    addEdge(4, 8);
    addEdge(5, 8);
    addEdge(6, 7);
    addEdge(7, 8);
    addEdge(8, 10);
 
    // Function Call
    printOrder(n, m);
    return 0;
}


Java
// Java program for the above approach
import java.util.*;
 
class GFG{
     
static final int maxN = 100000;
 
// Adjacency List to store the graph
@SuppressWarnings("unchecked")
static Vector []graph = new Vector[maxN];
 
// Array to store the in-degree of node
static int []indegree = new int[maxN];
 
// Array to store the time in which
// the job i can be done
static int []job = new int[maxN];
 
// Function to add directed edge
// between two vertices
static void addEdge(int u, int v)
{
     
    // Insert edge from u to v
    graph[u].add(v);
 
    // Increasing the indegree
    // of vertex v
    indegree[v]++;
}
 
// Function to find the minimum time
// needed by each node to get the task
static void printOrder(int n, int m)
{
     
    // Find the topo sort order
    // using the indegree approach
 
    // Queue to store the
    // nodes while processing
    Queue q = new LinkedList<>();
     
    // Pushing all the vertex in the
    // queue whose in-degree is 0
 
    // Update the time of the jobs
    // who don't require any job to
    // be completed before this job
    for(int i = 1; i <= n; i++)
    {
        if (indegree[i] == 0)
        {
            q.add(i);
            job[i] = 1;
        }
    }
 
    // Iterate until queue is empty
    while (!q.isEmpty())
    {
 
        // Get front element of queue
        int cur = q.peek();
 
        // Pop the front element
        q.remove();
 
        for(int adj : graph[cur])
        {
             
            // Decrease in-degree of
            // the current node
            indegree[adj]--;
 
            // Push its adjacent elements
            if (indegree[adj] == 0){
                job[adj] = 1 + job[cur];
                q.add(adj);
            }
        }
    }
 
    // Print the time to complete
    // the job
    for(int i = 1; i <= n; i++)
        System.out.print(job[i] + " ");
    System.out.print("\n");
}
 
// Driver Code
public static void main(String[] args)
{
     
    // Given Nodes N and edges M
    int n, m;
    n = 10;
    m = 13;
     
    for(int i = 0; i < graph.length; i++)
        graph[i] = new Vector();
         
    // Given directed edges of graph
    addEdge(1, 3);
    addEdge(1, 4);
    addEdge(1, 5);
    addEdge(2, 3);
    addEdge(2, 8);
    addEdge(2, 9);
    addEdge(3, 6);
    addEdge(4, 6);
    addEdge(4, 8);
    addEdge(5, 8);
    addEdge(6, 7);
    addEdge(7, 8);
    addEdge(8, 10);
 
    // Function call
    printOrder(n, m);
}
}
 
// This code is contributed by Amit Katiyar


Python3
# Python3 program for the above approach
from collections import defaultdict
 
# Class to represent a graph
class Graph:
     
    def __init__(self, vertices, edges):
         
        # Dictionary containing adjacency List
        self.graph = defaultdict(list)
         
        # No. of vertices
        self.n = vertices 
         
        # No. of edges
        self.m = edges 
         
    # Function to add an edge to graph
    def addEdge(self, u, v):
        self.graph[u].append(v)
     
    # Function to find the minimum time
    # needed by each node to get the task
    def printOrder(self, n, m):
       
        # Create a vector to store indegrees of all
        # vertices. Initialize all indegrees as 0.
        indegree = [0] * (self.n + 1)
         
        # Traverse adjacency lists to fill indegrees
        # of vertices. This step takes O(V + E) time
        for i in self.graph:
            for j in self.graph[i]:
                indegree[j] += 1
                 
        # Array to store the time in which
        # the job i can be done
        job = [0] * (self.n + 1)
         
        # Create an queue and enqueue all
        # vertices with indegree 0
        q = []
         
        # Update the time of the jobs
        # who don't require any job to
        # be completed before this job
        for i in range(1, self.n + 1):
            if indegree[i] == 0:
                q.append(i)
                job[i] = 1
                 
        # Iterate until queue is empty
        while q:
             
            # Get front element of queue
            cur = q.pop(0)
             
            for adj in self.graph[cur]:
                 
                # Decrease in-degree of
                # the current node
                indegree[adj] -= 1
               
                # Push its adjacent elements
                if (indegree[adj] == 0):
                    job[adj] =  1 + job[cur]
                    q.append(adj)
                     
        # Print the time to complete
        # the job
        for i in range(1, n + 1):
            print(job[i], end = " ")
             
        print()
 
# Driver Code
 
# Given Nodes N and edges M
n = 10
m = 13
 
g = Graph(n, m)
 
# Given Directed Edges of graph
g.addEdge(1, 3)
g.addEdge(1, 4)
g.addEdge(1, 5)
g.addEdge(2, 3)
g.addEdge(2, 8)
g.addEdge(2, 9)
g.addEdge(3, 6)
g.addEdge(4, 6)
g.addEdge(4, 8)
g.addEdge(5, 8)
g.addEdge(6, 7)
g.addEdge(7, 8)
g.addEdge(8, 10)
 
# Function Call
g.printOrder(n, m)
 
# This code is contributed by Aanchal Tiwari


C#
// C# program for the above approach
using System;
using System.Collections.Generic;
 
class GFG{
     
static readonly int maxN = 100000;
 
// Adjacency List to store the graph
static List []graph = new List[maxN];
 
// Array to store the in-degree of node
static int []indegree = new int[maxN];
 
// Array to store the time in which
// the job i can be done
static int []job = new int[maxN];
 
// Function to add directed edge
// between two vertices
static void addEdge(int u, int v)
{
     
    // Insert edge from u to v
    graph[u].Add(v);
 
    // Increasing the indegree
    // of vertex v
    indegree[v]++;
}
 
// Function to find the minimum time
// needed by each node to get the task
static void printOrder(int n, int m)
{
     
    // Find the topo sort order
    // using the indegree approach
 
    // Queue to store the
    // nodes while processing
    Queue q = new Queue();
     
    // Pushing all the vertex in the
    // queue whose in-degree is 0
 
    // Update the time of the jobs
    // who don't require any job to
    // be completed before this job
    for(int i = 1; i <= n; i++)
    {
        if (indegree[i] == 0)
        {
            q.Enqueue(i);
            job[i] = 1;
        }
    }
 
    // Iterate until queue is empty
    while (q.Count != 0)
    {
 
        // Get front element of queue
        int cur = q.Peek();
 
        // Pop the front element
        q.Dequeue();
 
        foreach(int adj in graph[cur])
        {
             
            // Decrease in-degree of
            // the current node
            indegree[adj]--;
 
            // Push its adjacent elements
            if (indegree[adj] == 0){
                job[adj] = 1 + job[cur];
                q.Enqueue(adj);
            }
        }
    }
 
    // Print the time to complete
    // the job
    for(int i = 1; i <= n; i++)
        Console.Write(job[i] + " ");
         
    Console.Write("\n");
}
 
// Driver Code
public static void Main(String[] args)
{
     
    // Given Nodes N and edges M
    int n, m;
    n = 10;
    m = 13;
     
    for(int i = 0; i < graph.Length; i++)
        graph[i] = new List();
         
    // Given directed edges of graph
    addEdge(1, 3);
    addEdge(1, 4);
    addEdge(1, 5);
    addEdge(2, 3);
    addEdge(2, 8);
    addEdge(2, 9);
    addEdge(3, 6);
    addEdge(4, 6);
    addEdge(4, 8);
    addEdge(5, 8);
    addEdge(6, 7);
    addEdge(7, 8);
    addEdge(8, 10);
 
    // Function call
    printOrder(n, m);
}
}
 
// This code is contributed by Amit Katiyar


输出:
1 1 2 2 2 3 4 5 2 6

时间复杂度: O(V + E),其中V是节点数,E是边数。
辅助空间: O(V)