首页 > 其他分享 >拓扑排序专题篇

拓扑排序专题篇

时间:2024-09-18 12:24:00浏览次数:10  
标签:专题 int 拓扑 入度 numCourses vector push 排序 节点

目录

前言

课程表

课程表II

课程表IV

火星词典


前言

拓扑排序是指对一个有向无环图的节点进行排序之后得到的序列,如果存在一条从节点A指向节点B的边,那么在拓扑排序的序列中节点A出现在节点B的前面。一个有向无环图可以有一个或多个拓扑排序序列,但无向图或有向图都不存在拓扑排序。

一种常用的拓扑排序算法是每次从有向无环图中取出一个入度为0的节点添加到拓扑排序序列之中,然后删除该节点及所有以他为起点的边。重复这个步骤,直到图为空或图中不存在入度为0的节点。如果最终图为空,那么图是有向无环图,此时就找到了该图的一个拓扑排序序列。如果最终图不为空并且已经不存在入度为0的节点,那么该图一定有环。

课程表

题目

思路

首先先建图,可以采用邻接矩阵或者邻接表建图,解题时采用邻接表来建图,并统计每个节点的入度,然后扫描所有节点的入度,将入度尾0的节点加入到队列中,取出队头元素,将该节点加入数组中,并将以该节点为起始点的边的终点的入度-1,如果有节点的入度为0,就将该节点加入队列中,最后,如果数组的大小和课程数目不相等,说明存在环,不能修完课程;否则能修完课程。

代码

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        vector<int> in(numCourses);
        vector<vector<int>> vv(numCourses);
        vector<int> v;
        for(auto it:prerequisites){
            vv[it[1]].push_back(it[0]);
            in[it[0]]++;
        }
        queue<int> q;
        for(int i=0;i<numCourses;i++)
            if(in[i]==0) q.push(i);
        while(!q.empty()){
            int ret=q.front();
            q.pop();
            v.push_back(ret);
            for(int x:vv[ret])
                if(--in[x]==0)
                    q.push(x);
        }
        if(v.size()==numCourses) return true;
        else return false;
    }
};
课程表II

题目

思路

这道题和上一道题其实是一样的,只不过是问题不同而已,解决方法还是首先先建图,可以采用邻接矩阵或者邻接表建图,解题时采用邻接表来建图,并统计每个节点的入度,然后扫描所有节点的入度,将入度尾0的节点加入到队列中,取出队头元素,将该节点加入数组中,并将以该节点为起始点的边的终点的入度-1,如果有节点的入度为0,就将该节点加入队列中,最后,如果数组的大小和课程数目不相等,说明存在环,不能修完课程;否则能修完课程。

代码

class Solution {
public:
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        unordered_map<int,vector<int>> hash;
        vector<int> in(numCourses);
        vector<int> ret;
        for(auto it:prerequisites){
            hash[it[1]].push_back(it[0]);
            in[it[0]]++;
        }
        queue<int> q;
        for(int i=0;i<numCourses;i++)
            if(in[i]==0) q.push(i);
        while(!q.empty()){
            int top=q.front();q.pop();
            ret.push_back(top);
            for(int x:hash[top])
                if(--in[x]==0)
                    q.push(x);
        }
        if(ret.size()==numCourses) return ret;
        else return {};
    }
};



// class Solution {
// public:
//     vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
//         vector<int> in(numCourses);
//         vector<vector<int>> vv(numCourses);
//         vector<int> ret;
//         for(auto it:prerequisites){
//             vv[it[1]].push_back(it[0]);
//             in[it[0]]++;
//         }
//         queue<int> q;
//         for(int i=0;i<numCourses;i++)
//             if(in[i]==0) q.push(i);
//         while(!q.empty()){
//             int top=q.front();q.pop();
//             ret.push_back(top);
//             for(int x:vv[top])
//                 if(--in[x]==0)
//                     q.push(x);
//         }
//         if(ret.size()==numCourses) return ret;
//         else return {};
//     }
// };
课程表IV

题目

思路

虽然这道题和前两道题看起来是一样的,但是这道题比前两道题要难一些,因为对于每一遍扫描到的入度为0的节点,这些节点之间是没有先决条件关系的,如果还用之前的解法,会把每一遍扫描到的入度为0的节点赋予先决条件,因此我们需要使用别的方法。

下面,先使用邻接表建图,然后扫描每个节点,进行深度优先遍历,如果该节点没有被遍历过,则遍历以该节点为起始点的所有边的终点,依旧是判断该节点有没有被遍历过,如果没有被遍历过,则遍历以该节点为起始点的所有边的终点,然后将邻接矩阵中的起始点到终点的值置为true,然后遍历所有终点,看是否存在以终点为起始点的点,然后将邻接矩阵中起始点到终点的终点的值置为isPre[pos][i]=isPre[pos][i]|isPre[x][i]。

代码

class Solution {
public:
    vector<bool> checkIfPrerequisite(int numCourses, vector<vector<int>>& prerequisites, vector<vector<int>>& queries) {
        vector<vector<int>> edges(numCourses);
        vector<bool> vis(numCourses,false);
        vector<vector<bool>> isPre(numCourses,vector<bool>(numCourses,false));
        for(auto& p:prerequisites)
            edges[p[0]].push_back(p[1]);
        for(int i=0;i<numCourses;i++)
            dfs(edges,isPre,vis,i);
        vector<bool> res;
        for(auto& query:queries)
            res.push_back(isPre[query[0]][query[1]]);
        return res;
    }

    void dfs(vector<vector<int>>& edges,vector<vector<bool>>& isPre,vector<bool>& vis,int pos){
        if(vis[pos]) return;
        vis[pos]=true;
        for(int x:edges[pos]){
            dfs(edges,isPre,vis,x);
            isPre[pos][x]=true;
            for(int i=0;i<isPre.size();i++)
                isPre[pos][i]=isPre[pos][i]|isPre[x][i];
        }
    }
};





//chatGpt的答案
// class Solution {
// public:
//     vector<bool> checkIfPrerequisite(int numCourses, vector<vector<int>>& prerequisites, vector<vector<int>>& queries) {
//         vector<vector<int>> adjacencyList(numCourses);
//         vector<vector<int>> successors(numCourses);
//         vector<bool> visited(numCourses, false);
//         unordered_map<int, int> topoOrderIndex;  // Store the index of each course in topological order
//         queue<int> q;
        
//         // Construct adjacency list and initialize in-degree counts
//         vector<int> inDegree(numCourses, 0);
//         for (const auto& prerequisite : prerequisites) {
//             int course = prerequisite[0];
//             int prerequisiteCourse = prerequisite[1];
//             adjacencyList[course].push_back(prerequisiteCourse);
//             inDegree[prerequisiteCourse]++;
//         }
        
//         // Perform topological sort and record the order
//         for (int i = 0; i < numCourses; ++i) {
//             if (inDegree[i] == 0) {
//                 q.push(i);
//             }
//         }
//         int topoIndex = 0;
//         while (!q.empty()) {
//             int current = q.front();
//             q.pop();
//             topoOrderIndex[current] = topoIndex++;
//             for (int successor : adjacencyList[current]) {
//                 if (--inDegree[successor] == 0) {
//                     q.push(successor);
//                 }
//                 successors[current].push_back(successor);
//             }
//         }
        
//         // Handle queries
//         vector<bool> results;
//         for (const auto& query : queries) {
//             int courseA = query[0];
//             int courseB = query[1];
//             bool isPrerequisite = dfs(courseA, courseB, successors, visited, topoOrderIndex);
//             results.push_back(isPrerequisite);
//             fill(visited.begin(), visited.end(), false); // Reset visited for the next query
//         }
        
//         return results;
//     }
    
// private:
//     bool dfs(int courseA, int courseB, const vector<vector<int>>& successors, vector<bool>& visited, const unordered_map<int, int>& topoOrderIndex) {
//         if (courseA == courseB) {
//             return true;
//         }
//         visited[courseA] = true;
//         for (int successor : successors[courseA]) {
//             if (!visited[successor] && (topoOrderIndex.at(courseA) < topoOrderIndex.at(successor))) {
//                 if (successor == courseB || dfs(successor, courseB, successors, visited, topoOrderIndex)) {
//                     return true;
//                 }
//             }
//         }
//         return false;
//     }
// };
火星词典

题目

思路

这道题的题目首先得看懂,然后解析所有字符串,两个字符串满足前一个字符串的前n个字符和后一个字符串的前n个字符相同,第一次出现不同字符时,前一个字符串的第n+1个字符的序列小于后一个字符串的第n+1个字符的序列,如果第一个字符串的长度大于第二个字符串的长度,且第一个字符串的长度为第二个字符串长度的字符和第二个字符串相等,这样是不符合题意的,直接返回空串;否则就建立邻接表,并统计所有节点的入度信息,将入度为0的节点的值加入队列,然后取出队头元素,将该节点加入字符串末尾,并将以该节点为起始点的边的终点的入度-1,如果有节点的入度为0,就将该节点加入队列中,执行将该节点加入字符串末尾,并将以该节点为起始点的边的终点的入度-1,如果有节点的入度为0,就将该节点加入队列中。

最后扫描数组,如果存在某个节点的入度不为0,说明存在环,不能排序,返回空串;否则返回结果字符串。

代码

class Solution {
    unordered_map<char,unordered_set<char>> edges;
    unordered_map<char,int> in;
    bool flag;
public:
    string alienOrder(vector<string>& words) {
        for(string s:words)
            for(char ch:s)
                in[ch]=0;
        int n=words.size();
        for(int i=0;i<n-1;i++)
            for(int j=i+1;j<n;j++){
                helper(words[i],words[j]);
                if(flag) return "";
            }
        queue<char> q;
        string s;
        for(auto& [a,b]:in){
            if(b==0) q.push(a);
        }
        while(!q.empty()){
            int ch=q.front();q.pop();
            s+=ch;
            for(char c:edges[ch])
                if(--in[c]==0)
                    q.push(c);
        }
        for(auto& [a,b]:in)
            if(b!=0) return "";
        return s;
    }

    void helper(string& s1,string& s2){
        int n=min(s1.size(),s2.size());
        int i=0;
        for(;i<n;i++)
            if(s1[i]!=s2[i]){
                char a=s1[i],b=s2[i];
                if(!edges.count(a) || !edges[a].count(b)){
                    edges[a].insert(b);
                    in[b]++;
                }
                break;
            }
        if(i==s2.size() && i<s1.size())
            flag=true;
    }
};

标签:专题,int,拓扑,入度,numCourses,vector,push,排序,节点
From: https://blog.csdn.net/wmh_1234567/article/details/140551710

相关文章

  • 织梦dedecms使用weight排序无效怎么办
    织梦CMS(DedeCMS)中使用 weight 排序无效的问题,通常是因为程序内部的排序逻辑存在问题。根据之前提供的信息,这个问题在DedeCMS5.7版本中存在,并且可以通过修改底层代码来解决。下面是解决此问题的一般步骤:解决方法定位代码:首先,找到织梦CMS的 plus 目录下的 listinfo.......
  • JavaScript:对组织值进行排序
    要对组织值进行排序,你可以使用JavaScript中的数组排序方法 sort()。下面是一些示例代码,展示如何对不同类型的组织值进行排序:示例1:对数字数组进行排序constnumbers=[5,2,9,1,5,6];//使用sort()方法进行升序排序numbers.sort((a,b)=>a-b);console.log(n......
  • 信息学奥赛初赛天天练-91-CSP-S2023基础题3-编译命令、树的重心、拓扑排序、进制转换
    PDF文档公众号回复关键字:202409172023CSP-S选择题1单项选择题(共15题,每题2分,共计30分:每题有且仅有一个正确选项)11以下哪个命令,能将一个名为main.cpp的C++源文件,编译并生成一个名为main的可执行文件?()Ag++-omainmain.cppBg++-omain.cppmainCg++......
  • 冒泡排序(重要!)
    1.作用比较数组中两个相邻的数,如果第一个数比第二个数大,则会交换位置。每一次比较都会产出最大或是最小的数,下一轮则可以少一次排序,依次循环,直到结束2.机制冒泡排序分为两个循环,外层冒泡轮数(总的次数循环),而内层比较大小(两个数进行比较)可以想象有三个杯子,假如1号大于2号,需要把......
  • 【数据结构】线性表作业——归并排序
    【问题描述】有一个含n(n<=200000)个整数的无序序列,采用链表的二路归并排序实现递增排序【输入形式】一行字符串,包含多个整数,每个数之间用空格分开。【输出形式】递增排序的结果,每个数之间用空格分开。【样例输入】947625813【样例输出】12345......
  • C# 链表排序之插入排序
    在C#中,对于链表(如LinkedList<T>)进行排序,插入排序是一个可行的选择,尽管它可能不是最高效的排序方法,特别是当链表很长时。插入排序的基本思想是将链表分成已排序和未排序的两部分,初始时,已排序部分只包含链表的第一个元素,然后依次将未排序部分的元素插入到已排序部分的适当位置......
  • 冒泡排序
    点击查看代码packageSort;importjava.util.Arrays;//每一轮外层循环都会固定一个最大或最小的数到后面去,然后内层循环继续从0开始到最后未排序的数组末项publicclassBubbleSort{publicstaticvoidmain(String[]args){int[]a={2,3,0,8......
  • [Python手撕]归并排序
    classSolution:defsortArray(self,nums:List[int])->List[int]:defmerge(nums1,nums2):ifnotnums1andnotnums2:returnNoneifnotnums1:returnnums2ifnotnums2......
  • 列表与克隆体专题 scratch 20240916_182231
    体验克隆体变量scratch20240916_153936_鲸鱼编程pyhui的技术博客_51CTO博客https://blog.51cto.com/u_13137233/12031738数据的容器列表scratch20240916_155811_鲸鱼编程pyhui的技术博客_51CTO博客https://blog.51cto.com/u_13137233/12031757多组列表共同表达同一数据sc......
  • 插入排序
    点击查看代码packageSort;importjava.util.*;//插入排序:扑克牌从第二张开始往前排,相当于分成已排区跟待排区publicclass插入{publicstaticvoidmain(String[]args){int[]a={3,4,8,1,13,15,11,9,2,0};//排序for(inti=1;i<a.leng......