207. Course Schedule(课程安排)

207. Course Schedule(课程安排)

浏览更多内容,可访问:http://www.growai.cn

1 问题描述

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?

已知有n个课程,标记从0至n-1,课程之间是有依赖关系的,例如希望完成0课程,可能需要先完成1课程。已知n个课程的依赖关系,求是否可以将n个课程全部完成。

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.

2 思路

  • 使用深度优先遍历:对输入进行分析,原始问题可以转换为有向图问题,当有向图无环时返回True,当有向图有环时返回False
  • 使用宽度优先遍历:只将入度为0的点添加至队列。当完成一个顶点的搜索(从队 列取出),它指向的所有顶点入度都减1,若此时某顶点入度为0则添加至队列,若完 成宽度搜索后,所有的点入度都为0,则图无环,否则有环。

3 C++实现

  • 图的实现
struct GraphNode{
	int label;
	std::vector<GraphNode *> neighbors;
	GraphNode(int x) : label(x) {};
};
  • 方法一:深度优先遍历
class Solution {
public:
    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<GraphNode *> graph;
        vector<int> visit;
        //创建图
        for(int i=0; i<numCourses; i++) {
            graph.push_back(new GraphNode(i));
            visit.push_back(-1);
        }

        //连接图
        for(int i=0; i<prerequisites.size(); i++) {
            GraphNode* begin = graph[prerequisites[i].second];
            GraphNode* end = graph[prerequisites[i].first];
            begin->neighbors.push_back(end);
        }

        //遍历
        for(int i=0; i<graph.size(); i++) {
            if(visit[i] == -1 && !DFS_graph(graph[i], visit))
                return false;
        }
        //回收内存
        for(int i=0; i<graph.size(); i++) {
            delete graph[i];
        }

        return true;
    }

private:
    bool DFS_graph(GraphNode *node, vector<int> &visit) {
        //节点访问控制,-1表示没有访问,0表示正在访问,1表示访问完成
        visit[node->label] = 0;
        for(int i=0; i<node->neighbors.size(); i++) {
            if(visit[node->neighbors[i]->label] == -1) {
                if(DFS_graph(node->neighbors[i], visit) == 0)
                    return false;
            }
            else if(visit[node->neighbors[i]->label] == 0)
                return false;
        }
        visit[node->label] = 1;
        return true;
    }
};
  • 方法二,宽度优先(拓扑结构)
class Solution {
public:
    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<GraphNode *> graph;
        vector<int> degree;
        //创建图
        for(int i=0; i<numCourses; i++) {
            graph.push_back(new GraphNode(i));
            degree.push_back(0);
        }

        //连接图
        for(int i=0; i<prerequisites.size(); i++) {
            GraphNode* begin = graph[prerequisites[i].second];
            GraphNode* end = graph[prerequisites[i].first];
            begin->neighbors.push_back(end);
            degree[prerequisites[i].first]++;
        }

        queue<GraphNode *> Q;
        for(int i=0; i<degree.size(); i++) {
            if(degree[i] == 0)
                Q.push(graph[i]);
        }

        while(!Q.empty()) {
            GraphNode* node = Q.front();
            Q.pop();
            for(int i=0; i<node->neighbors.size(); i++) {
                degree[node->neighbors[i]->label]--;
                if(degree[node->neighbors[i]->label] == 0)
                    Q.push(node->neighbors[i]);
            }
        }

        //回收内存
        for(int i=0; i<graph.size(); i++) {
            delete graph[i];
        }

        //回收内存
        for(int i=0; i<degree.size(); i++) {
            if (degree[i]){
                return false;
            }
        }
        return true;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值