【第十八周】207. Course Schedule

原题

There are a total of n courses you have to take, labeled from 0 to n - 1.

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]

Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?

For example:

2, [[1,0]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.

2, [[1,0],[0,1]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.

Note:
1,The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
2,You may assume that there are no duplicate edges in the input prerequisites.

leetCode地址:https://leetcode.com/problems/course-schedule/description/

解题思路

题目大意:有n门课程,其中有些课程是有先决条件的,例如[1, 2]表示必须先上完课程2,才能上课程1。给出课程数与所有先决条件,求是否能学完所有课程。

我们可以将一门课程作为图的一个节点,一个先决条件就是一条有向边,就可以将此问题转化为关于图问题了。我们要知道能不能上完所有课程,其实要求的就是,图里有没有环路。如果图里有环,就不能上完所有课程。
现在问题变成了—验证有向图是否有环。
验证环路的解法有很多种,例如可以使用拓扑排序来验证:如果对所有节点的拓扑排序能够完成,那么图里就没有环,否则就有环。拓扑排序的方法也有两种,这里就不再一一展开。

我们也可以利用DFS遍历来进行验证,不过这里的DFS需要一点处理。

每个节点在遍历过程中有三种状态:0表示未访问,1表示正在访问其子节点,2表示此节点以及其所有子节点均已访问。
这三种状态有什么用处呢?当我们遍历到某个节点,如果此节点的状态为0或者2,都没有问题;但如果状态为1,就表明此处形成了环。为什么呢?因为状态为1时,表示正在遍历其子节点;而子节点又能够访问到它,必须要有回路才能做到。
通过以上思路就可以设计出DFS求解的算法。

代码

class Solution {
public:
    int visited[10000];    //节点的状态保存

    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
        map<int, vector<int> > graph;
        //初始化过程
        for (int i = 0; i < numCourses; i++ ) {
            vector<int> temp;
            graph[i] = temp;
        }

        //所有节点的状态初始化为状态0
        for (int& i : visited) i = 0;

        //构建有向图
        for (auto i : prerequisites) {
            graph[i.first].push_back(i.second);
        }

        //对每个节点都进行dfs检验
        for (int i = 0; i < numCourses; i++) {
            if (visited[i] == 0) {
                if (!dfs(graph, i)) return false;
            }
        }
        return true;
    }
    bool dfs(map<int, vector<int> >& graph, int t) {
        if (visited[t] == 1) return false;

        //遍历子节点之前,将状态设为1
        visited[t] = 1;

        // 开始遍历子节点
        for (auto i : graph[t]) {
            if (dfs(graph, i) == false) return false;
        }

        // 遍历完成后,状态设为2
        visited[t] = 2;
        return true;
    }
};

总结

1、有向图的环路检验
2、dfs算法
3、拓扑排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值