No207. Course Schedule

来源:互联网 发布:淘宝助理快速发布宝贝 编辑:程序博客网 时间:2024/06/11 09:15

一、题目描述

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.

二、我的解法

1、解题思路


一个图中的边可以分为树边、前向边、回边和横边,我们重点关注前向边、回边和横边的性质。如果采用DFS对图进行搜一遍,并且按照访问和返回的顺序,对图中的每个节点进行标号,左边的数字(pre)表示访问的序号,右边的数字(post)表示返回的序号,则一幅图可以表示为以下状态:


其中假定一条边是右v指向u:v—>u,则有如下性质:

回边:pre(v)>pre(u) , post(v)<post(u)

前向边:pre(v)<pre(u) , post(v)>post(u)

横边:pre(v)>pre(u) , post(v)>post(u)

所以根据给出的信息,构建图,然后根据图的结构构建DFS访问后每个节点的pre和post值,最后根据pre和post值检查图中是否含有回边,如果包含回边,则图中有环。

用vector<unordered_set<int>>存储图的信息,用vector<pair<int,int>>存储pre和post值,全局变量count表示访问和返回的顺序,函数dfs表示深度优先遍历图,并对遍历的每个节点标记pre和post。

2、代码实现

class Solution {public:    int count =0;    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {        vector<unordered_set<int>> graph(numCourses);        for(auto p:prerequisites){            graph[p.second].insert(p.first);        }        vector<pair<int,int>> point(numCourses,make_pair(0,0));        for(int i=0;i<numCourses;i++){            dfs(graph,point,i);        }        for(int v=0;v<numCourses;v++)            for(int u:graph[v])                if(point[v].first>point[u].first&&point[v].second<point[u].second)                    return false;        return true;    }    void dfs(vector<unordered_set<int>>& graph,vector<pair<int,int>>& point,int node){        if(point[node].first==0){            point[node].first=++count;            for(auto neigh:graph[node])                dfs(graph,point,neigh);            point[node].second=++count;        }    }};
三、其它解法一

1、解题思路

DFS遍历图,如果在一条搜索路径中,访问了该路径中已经访问过的节点,则说明有环。该方法需要注意的是,要创建两个vector:visited和onpath,其中visited用于记录各条路径中已经访问过的节点,目的是为了避免重复访问节点,已经访问过的就不用在访问了,而onpath是用于记录一条路径中访问过的节点,用于检查是否有环,所以在路径访问结束之后,onpath中的值要清空,代码中visited和onpath都是用true表示访问过,false表示未访问。

2、代码实现

class Solution {public:    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {        vector<unordered_set<int>> graph(numCourses);        for(auto p:prerequisites)            graph[p.second].insert(p.first);        vector<bool> visited(numCourses,false);        vector<bool> onpath(numCourses,false);        for(int i=0;i<numCourses;i++)            if(!visited[i]&&dfs_circle(graph,i,visited,onpath))                return false;        return true;    }    bool dfs_circle(vector<unordered_set<int>>& graph,int node,vector<bool>& visited,vector<bool>& onpath){        if(visited[node])return false;        onpath[node]=visited[node]=true;        for(auto neigh:graph[node])            if(onpath[neigh]||dfs_circle(graph,neigh,visited,onpath))                return true;        onpath[node] = false;        return false;    }};

四、其它解法二

1、解题思路

BFS遍历图,并通过compute_indegree函数记录每个节点的入度。然后遍历图,如果没有一个节点的入度为0,则有环,如果有至少一个节点的入度为0,则暂时无环,将入度为0的节点标记下来,其它所有与该入度为0的节点相连的节点的入度减一,直至把所有节点都遍历完。

2、代码实现

class Solution {public:    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {        vector<unordered_set<int>> graph(numCourses);        for (auto pre : prerequisites)            graph[pre.second].insert(pre.first);        vector<int> degrees = compute_indegree(graph);        for (int i = 0; i < numCourses; i++) {            int j = 0;            for (; j < numCourses; j++)                if (!degrees[j]) break;            if (j == numCourses) return false;            degrees[j] = -1;            for (int neigh : graph[j])                degrees[neigh]--;        }        return true;    }    vector<int> compute_indegree(vector<unordered_set<int>>& graph) {        vector<int> degrees(graph.size(), 0);        for (auto neighbors : graph)            for (int neigh : neighbors)                degrees[neigh]++;        return degrees;    }}; 

原创粉丝点击