leetcode207 课程表 中等

现在你总共有 n 门课需要选,记为 0 到 n-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。这是不可能的。

说明:

输入的先决条件是由边缘列表表示的图形,而不是邻接矩阵。详情请参见图的表示法。
你可以假定输入的先决条件中没有重复的边。

提示:

这个问题相当于查找一个循环是否存在于有向图中。如果存在循环,则不存在拓扑排序,因此不可能选取所有课程进行学习。
通过 DFS 进行拓扑排序 - 一个关于Coursera的精彩视频教程(21分钟),介绍拓扑排序的基本概念。
拓扑排序也可以通过 BFS 完成。

思路

下图为课程的依赖关系

  • 图1为可完成全部任务
  • 图2存在环:如果要修2课程,需要先修1课程,而修1课程的前提是修完2、3课程,存在冲突
    所以判断图是否存在环即可。
    在这里插入图片描述
    通过图的深搜来完成
  • 1、首先连接好图的结构,初始化label为-1,表示未访问过。0为正在访问,1为已访问完成
  • 2、dfs:
  • 开始第i节点,设visit[i]为0
  • 然后遍历它的相邻节点
  • if:相邻节点为-1,即未访问过,则dfs(相邻节点)
  • else if:相邻节点为0,即相邻节点为正在访问的节点,此时形成环,return false
  • 访问完全部相邻节点,且相邻节点也没有形成环,则都标记为1。
  • 3、完成return true。
    在这里插入图片描述
struct GraphNode{
    int label;
    std::vector<GraphNode*> neibhors;
    GraphNode(int x): label(x) {};
};
class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        std::vector<GraphNode*> graph;//图的邻接表
        std::vector<int> visit;//节点访问状态数组,-1 未防蚊,0 正在访问,1 访问过
        for(int i = 0; i < numCourses; i++){
            graph.push_back(new GraphNode(i));
            visit.push_back(-1);
        }//创建图的节点,new的一般要delet,visit初始化
        for(int i = 0; i < prerequisites.size(); i++){
            GraphNode *begin = graph[prerequisites[i][1]];
            GraphNode *end = graph[prerequisites[i][0]];
            begin->neibhors.push_back(end);
        }//由题,课程2指向课程1,按照图的实际意义,先学begin,在学end,箭头代表学习路径
        for (int i = 0; i < graph.size(); i++){//循环所有初始节点
			if (visit[i] == -1 && !DFS_graph(graph[i], visit)){
				return false;//如果节点没有被访问过,进行DFS,如果遇到环,返回false
			}
		}
		for (int i = 0; i < numCourses; i++){
			delete graph[i];
		}
		return true;
    }
private://visit -1表示还没被访问,0表示正在递归访问,1表示访问过
    bool DFS_graph(GraphNode *node, std::vector<int> &visit){
        visit[node->label] = 0;//标记此时正在访问node->label这个初始节点
        for(int i = 0; i < node->neibhors.size(); i++){//递归搜索初始节点全部邻接点
            if(visit[node->neibhors[i]->label] == -1){//如果邻接点没被访问过,下面开始深度递归访问
                if(DFS_graph(node->neibhors[i], visit) == 0){
                    return false;//如果递归没退出,遇到正在访问过程中的任何一个节点,返回0
                }
            }
            else if(visit[node->neibhors[i]->label] == 0){
                return false;//这就是两个课程,有环,直接就是自己遇到了自己,返回0
            }
        }
        visit[node->label] = 1;//访问过后,node->label标记为访问过了
        return true;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值