拓扑排序模板【广度优先搜索】

leetcode链接:

207. 课程表

一、题目描述:

        你这个学期必须选修numCourses门课程,记为0到numCourses-1。

        在选修某些课程之前需要一些先修课程。先修课程按数组prerequisites给出,其中prerequisites[i] = [ai, bi],表示如果学习课程ai则必须先学习课程bi。

        例如,先修课程对[0,1]表示:想要学习课程0,你需要先完成课程1。

        请你判断是否可能完成所有课程的学习?如果可以,返回true;否则,返回false。

        示例1:

                输入:numCourses=2,prerequisites=[[1,0]]

                输出:true

                解释:总共有2门课程。学习课程1之前,你需要完成课程0。这是可能的。

提示:

  • 1 <= numCourses <= 2000
  • 0 <= prerequisites.length <= 5000
  • prerequisites[i].length == 2
  • 0 <= ai, bi < numCourses
  • prerequisites[i] 中的所有课程对 互不相同

二、思路:

        考虑拓扑排序中最前面的节点,该节点一定没有任何入边,即没有任何的先修课程要求;

        当将一个节点加入答案后,就可以移除它的所有出边,代表着它的相邻节点少了一门先修课程的要求;

        如果某个相邻节点变成没有任何入边的节点,那么就代表这门课可以开始学习了;

        按照这种流程,不断将没有入边的节点加入答案,直到答案中包含所有的节点【拓扑排序】或者不存在没有入边的节点【有环】。

三、代码:

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        edges.resize(numCourses);
        indeg.resize(numCourses);
        for(auto info : prerequisites) {
            edges[info[1]].push_back(info[0]);
            ++indeg[info[0]];
        }

        queue<int> q;
        for(int i=0;i<numCourses;++i) {
            if(indeg[i] == 0) {
                q.push(i);//没有入边的节点
            }
        }

        int visited = 0;//按流程最终个数
        while(!q.empty()) {
            ++visited;
            int u = q.front();
            q.pop();
            for(int v : edges[u]) {
                --indeg[v];
                if(indeg[v] == 0) {//产生没有入边的节点
                    q.push(v);
                }
            }
        }
        return visited == numCourses;
    }
private:
    vector<vector<int>> edges;
    vector<int> indeg;
};

四、题目拓展:

        小米手机的生产制造过程依赖复杂的焊接,集成,封装,测试等流程,工序之间存在相互依赖,假设必须完成的 n 门工序,记为0到n-1,在完成某些工序之前需要先完成前置工序。其中[a:b],表示如果要完成工序a,必须先完成工序b,请你判断工序的编排是否合理,是否可能完成所有工序?如果可以,输出1,否则,输出0.

        样例:

                输入:2

                           1:0,0:1

                输出:0

注意:ACM模式下,考虑输入格式

#include<bits/stdc++.h>
using namespace std;

int num;
vector<vector<int>> edges;
vector<int> indeg;

int main() {

    scanf("%d", &num);
    edges.resize(num);
    indeg.resize(num);
    for(int i=0;i<num;++i) {
        int a, b;
        scanf("%d:%d", &a, &b);   //输入格式处理
        edges[b].push_back(a);
        ++indeg[a];
        if(i < num-1) getchar();  //,
    }

    queue<int> q;
    for(int i=0;i<num;++i) {
        if(indeg[i] == 0) {
            q.push(i);
        }
    }

    int visited = 0;
    while(!q.empty()) {
        ++visited;
        int u = q.front();
        q.pop();
        for(int v : edges[u]) {
            --indeg[v]
            if(indeg[v] == 0) {
                q.push(v);
            }
        }
    }

    if(visited == num) {
        cout << "1" << endl;  //输出
    } else {
        cout << "0" << endl;
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值