【课程表算法题--拓扑排序】

课程表1

你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1。在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]。给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?
示例 1:
输入: 2, [[1,0]]
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。

示例 2:
输入: 2, [[1,0],[0,1]]
输出: false
解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成​课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。

import java.util.Scanner;
import java.util.Stack;

public class Main{
    public static void main(String[] args){
         Scanner sc = new Scanner(System.in);  //eg:输入2
         int numCourse = sc.nextInt();
         sc.close();
         int[][] matrix = new int[][]{{1,0},{0,1}};
         System.out.println(ifFinishCourse(numCourse,matrix));
    
    }
  
    //函数ifFinishCourse,判断是否可以完成课程
    public static boolean ifFinishCourse(int numCourse,int[][] matrix){
         int[] indegree = new int[numCourse];
         for(int i=0;i<matrix.length;i++){
             indegree[matrix[i][1]]++;
         }
     
         //创建一个栈
         Stack<Integer> s = new Stack<>();
         for(int i=0;i<indegree.length;i++){
             if(indegree[i] == 0){
                 s.push(i);
             }
         }
     
        int count = 0;  //用于计数,判断是否有环

        while(!s.isEmpty()){
            int tempN = s.pop();
            count++;
            //更新入度数组
            for(int i=0;i<matrix.length;i++) {
                 if(matrix[i][0] == tempN){
                      indegree[matrix[i][1]]--;
                      if(indegree[matrix[i][1]] == 0){
                          s.push(matrix[i][1]);
                      }
                 }
            }
        }
        
        if(count<numCourse){
            return false;
        } else {
            return true;
        }
    }
}

课程表2

你这个学期必须选修 numCourse 门课程,记为 0 到 taskNum-1。在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]。给定课程总量以及它们的先决条件,请你判断完成所有课程的学习的最少次数,假设可以并行选修taskNum课程,请计算完成所有课程所需最短时间?
示例 1:
输入: 3
1
1>2
输出: 2
解释: 总共有 3 门课程,选修1个课程。学习课程 1 之前,你需要完成课程 2。总共需要2。
示例 2:
输入:9
6
1>2
2>3
2>4
4>5
6>4
8>7
输出: 4

import java.nio.charset.StandardCharsets;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Scanner;

/**
 * 拓扑排序
 *
 * @author
 * @DATE 2024/6/22
 **/
public class TopologicalSort {

    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in, StandardCharsets.UTF_8.name());
        int taskNum = cin.nextInt();
        int relationNum = cin.nextInt();
        int[][] relations = new int[relationNum][];
        if (relationNum > 0) {
            cin.nextLine();
            for (int i = 0; i < relationNum; i++) {
                String[] str = cin.nextLine().split(">");
                relations[i] = new int[2];
                relations[i][0] = Integer.parseInt(str[0]);
                relations[i][1] = Integer.parseInt(str[1]);
            }
        }
        cin.close();
        System.out.println(getMinTime(taskNum, relations));
    }

    private static int getMinTime(int taskNum, int[][] relations) {
        /**
         * 创建拓扑排序
         * 创建一个入度表
         * 遍历入度表,把入读为0的全部入队列
         * 队列出队,判断当前任务的入度是否为0,如果为0,加入队列,遍历完成就是最少次数
         */
        if (taskNum == 0) {
            return 0;
        }
        // 记录每个节点入度
        int[] num = new int[taskNum];
        for (int i = 0; i < relations.length; i++) {
            // 入度指的是一个点被多个边指向
            num[relations[i][0]]++;
        }
        Queue<Integer> queue = new ArrayDeque<>();
        for (int i = 0; i < taskNum; i++) {
            // 首先将入度为0的点添加到队列
            if (num[i] == 0) {
                queue.add(i);
            }
        }

        int time = 0;
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                // 当前节点出队时,将该节点的入度-1
                int temp = queue.poll();
                for (int j = 0; j < relations.length; j++) {
                    // relations[j][1]代表依赖节点 == 当前出队节点
                    if (relations[j][1] == temp) {
                        // 当前节点入度-1
                        num[relations[j][0]]--;
                        if (num[relations[j][0]] == 0) {
                            // 入度为0的当前节点,加入队列
                            queue.add(relations[j][0]);
                        }
                    }
                }
            }
            time++;
        }
        return time;
    }
}
  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值