Week2

#Week3
Graph
question source: Course Schedul

##question description
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.

  Example 1:       
        Input: 2, [[1,0]] 
        Output: true
        Explanation: There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.
       
  Example 2:      
        Input: 2, [[1,0],[0,1]]
        Output: false
        Explanation: 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.

这周学习了图,这是一个有向图类型的题目,学生要想学一门课,可能要必须先学习另一门课,理解题意之后就知道这题实际上是要求我们判断有向图是否有环,如果有环,就不可能完成所有课程。在教材第105页讲了一个有向无环图的性质,每个有向无环图至少含有一个源点和一个汇点,根据源点存在性的保证,给出一种线性化的算法:找到一个源点,输出它,然后将它从图中删除,重复以上过程直至图为空。 就利用此算法,先假设它是有向无环图,如果图不为空,说明不是。
删除了源点之后,源点所指的点的入度要相应地减少。
代码如下

class Solution {
public:
    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {

        vector< vector<int>> graph(numCourses);
        int degrees[numCourses];  
        memset(degrees, 0, sizeof(degrees));

        //[0,1] 1->0 have to finish 1 first
        for(auto i = prerequisites.begin(); i < prerequisites.end(); i++){
            int x = (*i).first;
            int y = (*i).second;
            graph[y].push_back(x);
            degrees[x]++;
        }  
        int i,j,k;
        for(i = 0; i < numCourses; i++){
            for(j = 0; j < numCourses; j++){
                if(degrees[j] == 0) break;         
            }
            if(j == numCourses) return false;
            degrees[j] --;
            for(auto val : graph[j]){
                degrees[val] --;
            }
        }
        return true;                                            
    }
};

开始的时候我是用二维数组来保存图的,然后一直出错,原因是不能分配这么大的空间,于是就改成了用vector< vector> graph(numCourses)的形式来储存图。这样更节省空间,而且更快。

question source: 升级版

这一题要求输出线性化的序列,在前面的代码里保存一下源点访问的顺序就行了,如果不符合,则返回空数组。
代码如下

class Solution {
public:
    vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector< vector<int>> graph(numCourses);
        vector<int> answer;
        int degrees[numCourses];  
        memset(degrees, 0, sizeof(degrees));

        //[0,1] 1->0 have to finish 1 first
        for(auto i = prerequisites.begin(); i < prerequisites.end(); i++){
            int x = (*i).first;
            int y = (*i).second;
            graph[y].push_back(x);
    
            degrees[x]++;
        }
        bool tag = true;

        int i,j,k;
        for(i = 0; i < numCourses; i++){
            for(j = 0; j < numCourses; j++){
                if(degrees[j] == 0) break;         
            }
            if(j == numCourses) {
                tag = false;
                break;
            }
            degrees[j] --;
            answer.push_back(j);            
            for(auto val : graph[j]){
                degrees[val] --;
            }
        }
        if(tag){
            return answer;
        }else{
            vector<int> a;
            return a;
        }                                                        
    }
};

书上还有另一种方法判断是否为有向无环图还可以构建DFS森林,有向无环图是不含有回边的。

猜你喜欢

转载自blog.csdn.net/pjsfirstlaw/article/details/82667884
今日推荐