Topological sorting of hand-in-hand Teaching

Posted by BLaZuRE on Thu, 30 Dec 2021 00:30:49 +0100

Topological sorting of hand-in-hand Teaching


In graph theory, * * Topological Sorting Is a linear sequence of all vertices of a directed acyclic graph (DAG) * *. And the sequence must meet the following two conditions:

  1. Each vertex appears only once.
  2. If there is A path from vertex A to vertex B, vertex A appears in front of vertex B in the sequence.

Only directed acyclic graphs (DAG) have topological sorting, and non DAG graphs have no topological sorting.

Topological sorting is generally applicable to dependent directed graphs, and can also be used to detect whether there are rings in directed graphs

process

  1. Mapping

  2. Record the penetration of each point

  3. Add the points that do not have access to the queue to see the dependency update access later

  4. Repeat 3 until the queue is empty

Tip: a pointless point is actually a point that has no dependency, that is, it can be accessed without other conditions

Mapping

I generally have three implementation forms

  • Implement your own graph class

  • Map < int, vector < int > >

  • Or use the form of adjacency table vector < list < int > >

Algorithm flow

Implementation of self graph class

class Graph {
 public:
  Graph(int n) {
    n_ = n;
    lst_.resize(n, list<int>());
    degree_.resize(n, 0);
  }

  void add(int v, int u) {
    lst_[v].push_back(u);
    ++degree_[u];
  }

 private:
  vector<list<int>> lst_;  // Adjacency table
  vector<int> degree_;     // Penetration
};

Examples

Simple version

207. Curriculum

Medium difficulty 916

You must take numCourses this semester, marked 0 to numCourses - 1.

Some prerequisite courses are required before taking some courses. Prerequisite courses are given by the array prerequisites, where prerequisites[i] = [ai, bi], which means that if you want to learn course ai, you must learn course bi first.

  • For example, the prerequisite course pair [0, 1] indicates that if you want to learn course 0, you need to complete course 1 first.

Please judge whether it is possible to complete all courses? If yes, return true; Otherwise, false is returned.

Example 1:

Input: numCourses = 2, prerequisites = [[1,0]]
Output: true
 Explanation: there are 2 courses in total. You need to complete course 0 before learning course 1. This is possible.

Example 2:

Input: numCourses = 2, prerequisites = [[1,0],[0,1]]
Output: false
 Explanation: there are 2 courses in total. Before learning course 1, you need to complete course 0; You should also complete course 1 before studying course 0. It's impossible.

Tips:

  • 1 <= numCourses <= 105
  • 0 <= prerequisites.length <= 5000
  • prerequisites[i].length == 2
  • 0 <= ai, bi < numCourses
  • All course pairs in prerequisites[i] are different from each other
class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        int n=prerequisites.size();
        vector<int> degree(numCourses,0); // Initialization penetration is 0
        // Mapping with adjacency table
        vector<list<int>> mp(numCourses);

        for(int i=0;i<n;i++) {
            mp[prerequisites[i][1]].push_back(prerequisites[i][0]);
            degree[prerequisites[i][0]]++;
        }

        // Start topology sorting
        queue<int> que;
        int count = 0;
        // How many points have been recorded
        for(int i=0;i<degree.size();i++) {
            if(degree[i]==0) {
                que.push(i);
            }
        }

        while(!que.empty()) {
            // The queue cannot be empty
            int val = que.front();
            que.pop();
            count++;
            auto vec = mp[val];
            for(auto i=vec.begin();i!=vec.end();i++) {
                degree[*i]--;  // Update penetration
                if(degree[*i]==0) {  // Join the queue with a penetration of 0
                    que.push(*i);
                }
            }
        }
        if(count==numCourses) { // exannulate
            return true;
        }

        return false; // Ring


    }
};

851. Noisy and rich

Medium difficulty 184

There are a group of n people as experimental subjects, numbered from 0 to n - 1, in which each person has different amounts of money and different degrees of quiet. For convenience, we call the person numbered X "person x" for short.

Give you an array richer, where richer[i] = [ai, bi] means that person ai has more money than person bi. Give you another integer array quiet, where quiet[i] is the quiet value of person i. The data logic given in richer is self consistent (that is, while person x is richer than person y, person y is not richer than person x).

Now, return an integer array answer as the answer, where answer[x] = y on the premise that person y is the quietest person (that is, the person with the smallest quiet value quiet[y]) among all people who must have no less than person x.

Example 1:

Input: richer = [[1,0],[2,1],[3,1],[3,7],[4,3],[5,3],[6,3]], quiet = [3,2,5,4,6,1,7,0]
Output:[5,5,2,5,4,5,6,7]
Explanation: 
answer[0] = 5,
person 5 than person 3 More money, person 3 than person 1 More money, person 1 than person 0 There is more money.
Only quiet (with low quiet value) quiet[x])Who are you person 7,
But it is unclear whether he is better than person 0 More money.
answer[7] = 7,
In all, you must have no less than person 7 Of people (this may include person 3,4,5,6 And 7),
Quietest (with lower quiet value) quiet[x])Who are you person 7. 
Other answers can be explained by similar reasoning.

Example 2:

Input: richer = [], quiet = [0]
Output:[0]

Tips:

  • n == quiet.length
  • 1 <= n <= 500
  • 0 <= quiet[i] < n
  • All values of quiet are different from each other
  • 0 <= richer.length <= n * (n - 1) / 2
  • 0 <= ai, bi < n
  • ai != bi
  • All number pairs in richer are different from each other
  • The observation of richer is logically consistent
class Solution {
public:
    vector<int> loudAndRich(vector<vector<int>>& richer, vector<int>& quiet) {
        degree_.resize(quiet.size(),0);
        vector<list<int>> graph_(quiet.size());
        /* 
            First build the map
         */
        for(auto v : richer) {
            // cout<<v[0]<<" "<<v[1]<<endl;
            graph_[v[0]].push_back(v[1]); // It represents the rich and points to the poor
            degree_[v[1]]++;
        }

        vector<int> ans(quiet.size(),-1);
        for(int i=0;i<ans.size();i++) {
            ans[i] = i;
        }
        // Start traversal
        // First, find the point with a penetration of 0, and if the penetration is 1, the result is yourself
        queue<int> que;
        for(int i=0;i<degree_.size();i++) {
            if(degree_[i]==0) {
                que.push(i);
            }
        }

        while(!que.empty()) {
            int index = que.front();
            que.pop();
            // cout<<"index: "<<index<<endl;
            for(auto v : graph_[index]) {
                // cout<<"v: "<<v<<endl;
                if(quiet[ans[v]]>quiet[ans[index]]) {
                    ans[v]=ans[index];
                }
                degree_[v]--;
                if(degree_[v]==0) {
                    que.push(v);
                }
            }

        }

        return ans;
    }

   

    private:
    vector<int> degree_; // Record penetration
    // vector<list<int>> graph_;
};

Topics: Algorithm Graph Theory