图论-DFS-拓扑排序

本文介绍了一种算法,用于判断在给定的课程先修条件列表下,是否能完成所有课程的学习。通过构建有向图并进行深度优先搜索,检查是否存在有向环,以此判断课程安排是否合理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


import java.util.ArrayList;
import java.util.List;

/**
 * 你这个学期必须选修 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。这是不可能的。
 *
 * 提示:
 *
 * 输入的先决条件是由 边缘列表 表示的图形,而不是 邻接矩阵 。详情请参见图的表示法。
 * 你可以假定输入的先决条件中没有重复的边。
 * 1 <= numCourses <= 10^5
 *
 */

public class CanFinish {
    public static void main(String[] args) {
        int[][] prerequisites = {{9, 6}, {9, 7}, {10, 7}, {10, 8}, {8, 5}, {7, 4}, {6, 3}, {5, 2}, {4, 1}, {4, 2},
            {3, 1}, {2, 0}, {1, 0}};

        CanFinishSolution s = new CanFinishSolution();
        boolean b = s.canFinish(11, prerequisites);
        System.out.println(b);
    }
}

class CanFinishSolution {
    List<List<Integer>> courses;
    int[] visited;
    boolean valid = true;

    public void init(int numCourses, int[][] prerequisites) {
        courses = new ArrayList<List<Integer>>();

        for (int i = 0; i < numCourses; i++) {
            courses.add(new ArrayList<Integer>());
        }

        for (int[] info : prerequisites) {
            courses.get(info[1]).add(info[0]);
        }

        visited = new int[numCourses];
    }

    public boolean canFinish(int numCourses, int[][] prerequisites) {
        if (numCourses < 1 || numCourses > Math.pow(10, 5)) {
            return false;
        }

        init(numCourses, prerequisites);

        for (int i = 0; i < numCourses; i++) {
            if (visited[i] == 0) {
                // visited == 0 表示未访问的节点
                dfs(i);
            }
        }

        return valid;
    }

    private void dfs(int u) {
        visited[u] = 1;  // visited == 1 表示节点访问中

        for (int v : courses.get(u)) {
            if (visited[v] == 0) {
                // 如果找到的节点没有被访问,则继续查找此节点的下一跳;
                dfs(v);
                if (!valid) {
                    return;
                }
            } else if (visited[v] == 1) {
                // 如果找到的节点正在访问中,则属于有向环图
                valid = false;
                return;
            }
            // 剩下的情况只有已经访问完毕,可以不用处理
        }

        visited[u] = 2;  // visited == 2 表示节点访问完毕
    }
}

运行结果:
true

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值