拓扑排序(以及leetcode207题解)

有向无环图:一个有向图不存在环,则称为有向无环图,简称DAG图。
AOV网:如果用DAG表示一个工程,其定点表示活动,用有向边< Vi,Vj>表示活动Vi必须先于活动Vj进行的这样一种关系,则将这种有向图称为定点表示活动的网络,记为AOV网。在AOV网中,活动Vi是活动Vj的前驱,活动Vj是Vi的直接后继,这种前驱和后继关系具有传递性,且任何活动Vi不能以它自己作为自己的前驱或后继。
拓扑排序:在图论中,有一个有向无环图的定点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序。
1)每个顶点只出现一次。
2)若顶点A在序列中排在顶点B的前面,则在图中不存在从顶点B到顶点A的路径。
对一个DAG图进行拓扑排序的算法有很多,比较常用的一种方法的步骤:
1)从DAG图中选择一个没有前驱的顶点并输出。
2)从图中删除该顶点和所有以它为起点的有向边。
3)重复1和2直到当前的DAG图为空或当前图中不存在无前驱的顶点为止。后一种情况则说明有向图中必然存在环。

leetcode207:
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.
解题思路:
  判断输入是否为拓扑排序,若是拓扑排序,返回true;否则返回false。
  
代码实现(以leetcode207为例):

class Solution {
public:
    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
        int Hash[10010];//每个节点的入度
        vector<vector<int>> v(numCourses);//用于存储每个节点相邻的边
        stack<int> s;//存放入度为0的节点
    memset(Hash, 0, sizeof(Hash));
    for(int i =0 ; i < prerequisites.size();i++){
        pair<int, int>p = prerequisites[i];
        int x = p.first;
        int y = p.second;
        cout<<"x = "<<x <<"y = "<<y<<endl;
        v[x].push_back(y);
        ++Hash[y];
    }
    for(int i = 0; i < numCourses; i++){
        if(Hash[i] == 0){
            s.push(i);
        }
    }
    while (!s.empty()) {
        int cur = s.top();//找到入度为0的点
        s.pop();
        for(int i = 0; i < prerequisites.size(); i++){
            pair<int, int>p = prerequisites[i];
            int x = p.first;
            int y = p.second;
            if(cur == x){
                for(int j = 0; j < v[cur].size(); j++){
                    --Hash[v[cur][j]];//删除以该点为起点的所有有向边
                    if(Hash[v[cur][j]] == 0)
                        s.push(v[cur][j]);
                }
                break;
            }
        }
    }
    for(int i = 0; i < numCourses; i++){
        if(Hash[i] != 0)
            return false;
    }
    return true;
    }
};

猜你喜欢

转载自blog.csdn.net/xiaomimi1993/article/details/81387180
今日推荐