判断有向图是否有环

696 阅读1分钟

二种方法:深度优先dfs、拓扑排序

dfs

对一个起始顶点进行dfs遍历,如果访问到了已经访问过的顶点,则有环,但是这个重复访问的顶点上一次访问必须是当前起始顶点发起的dfs访问的,如果是其他起始顶点发起的dfs遍历过这个点,则不是环;也就是说只有在同一次dfs遍历中重复访问到了某个节点才算是有环; 使用一个visited数组记录节点状态,0标识未被访问过,1标识在当前这次dfs遍历中被访问过,-1标识在当前dfs遍历中未被访问过,但是在其他dfs遍历中被访问过:

public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        vector<vector<int>> mmap(numCourses, vector<int>());
        vector<int> visited(numCourses, 0);
        for(int i=0; i<prerequisites.size(); i++)
            mmap[prerequisites[i][1]].push_back(prerequisites[i][0]);
        for(int i=0; i<numCourses; i++)
            if(!dfs(mmap, visited, i)) return false;
        return true;
    }

    bool dfs(vector<vector<int>>& mmap, vector<int>& visited, int k){
        if(visited[k] == 1) return false;
        if(visited[k] == -1) return true;
        visited[k] = 1;
        for(int i=0; i<mmap[k].size(); i++){
            if(!dfs(mmap, visited, mmap[k][i])) 
                return false;
        } 
        visited[k] = -1;
        return true;
    }
}

拓扑排序(广度优先)

核心思想是不断找没有前驱只有后继的节点压入栈或者队列,然后删去图中以它为前驱的边,输出这个节点(也就是计数器加1),直到没有这样的节点结束,此时若计数器和图中顶点个数相同,则无环,否则有:

bool tp(int numCourses, vector<vector<int>>& prerequisites) {
        vector<vector<int>> mmap(numCourses, vector<int>(numCourses, 0));
        vector<int> indegree(numCourses, 0);
        for(int i=0; i<prerequisites.size(); i++){
            mmap[prerequisites[i][0]][prerequisites[i][1]] = 1;
            indegree[prerequisites[i][0]] += 1;
        }
        stack<int> mstack;
        int res=0;
        for(int i=0; i<numCourses; i++)
            if(!indegree[i]) mstack.push(i);
        while(!mstack.empty()){
            int k = mstack.top();
            mstack.pop();
            res++;
            for(int i=0; i<numCourses; i++){
                if(mmap[i][k]){
                    mmap[i][k] = 0;
                    indegree[i]--;
                    if(!indegree[i]) mstack.push(i);
                }
            }
        }
        if(res < numCourses) return false;
        else return true;
}