leetcode207.课程表

判断有向图是否有环,拓扑排序

1.BFS(kahn算法)
参考:
https://leetcode.com/problems/course-schedule/discuss/58665/My-C%2B%2B-solution-23ms-beats-100-submissions

按照邻接表的格式保存图,同时计算每个节点的入度并保存。设置一个队列保存入度为0的点。每次取队头节点出队列,并将与其相邻的其他节点的入度减1,如果入度变为0则入队列。循环这一步骤。

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {//prerequisites的每个元素其实代表一条边
        vector<vector<int>> graph(numCourses);  //保存图,下标为每个节点,对应的vector为以该节点为首的其他节点
        vector<int> indegree(numCourses,0);  //保存每个节点的入度,下标为节点,值为入度
        for(auto edge:prerequisites)
        {
            graph[edge[1]].push_back(edge[0]);//edge[1]为首节点,比如(1,0)表示0指向1,0为首节点
            indegree[edge[0]]++; //1的入度加1
        }
        queue<int> zero_q; //保存入度为0的节点
        int count = 0;//统计节点总数
        for(int i=0;i<indegree.size();++i)
            if(indegree[i]==0)
                zero_q.push(i);  //入度为0的点入队列
        while(!zero_q.empty())
        {
            int node = zero_q.front();//出队列
            zero_q.pop();
            count++;
            for(auto elem:graph[node])
            {
                if(--indegree[elem]==0)//将以该节点为首节点的其他节点入度减1,如果减后入度为0,则入队列
                    zero_q.push(elem);
            }
        }
        return count==numCourses;


    }
};

2.DFS

从图中任一节点开始搜索,如果搜到递归路径上的点就说明有环。

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {//prerequisites的每个元素其实代表一条边
        vector<vector<int>> graph(numCourses);  //保存图,下标为每个节点,对应的vector为以该节点为首的其他节点
        vector<int> visited(numCourses,0); //用于保存一个节点是否被访问过,未访问为0,在当前路径正在被访问为1,在其他路径被访问过为2
        for(auto edge:prerequisites)
            graph[edge[1]].push_back(edge[0]);//edge[1]为首节点,比如(1,0)表示0指向1,0为首节点
        bool has_circle = false;
        for(int i=0;i<numCourses;++i) //从任一点开始搜索
        {
            if(has_circle== true) return false; //有环返回false,不写结果也是对的
            if(visited[i]==0) dfs(graph,i,visited,has_circle); //当前点未被访问过,则深度搜索
        }
        return !has_circle; //考虑最后一次搜索的结果
    }

    void dfs(const vector<vector<int>>& graph,int node,vector<int>& visited,bool &has_circle)//搜索的图是graph,当前搜到第node个节点了,visited表示每个点是否被搜过
    {
        if(visited[node]==1) //搜到了之前的节点,存在环
        {
            has_circle= true;
            return;
        }
        visited[node]=1; //标记当前点为1,表示要开始搜这个点了
        for(int i=0;i<graph[node].size();++i)  //搜和该点相连的点
        {
            dfs(graph,graph[node][i],visited,has_circle);
            if(has_circle) return; //如果搜到环了就提前停止搜索,不写超出时间限制
        }
        visited[node]=2; //这里标2是为了说明以该点为首无环,下次不必在搜索了。改成0也可以,只不过时间会增大,因为会重复搜索
    }
};

写法模板:
参考:https://blog.csdn.net/jiange_zh/article/details/48183267
BFS:

将所有入度为0的顶点加入队列q;
	while!q.empty() )
	{
		u = q.front();
		q.pop();
		list.push(u);
		for (u的每个邻接点v)
		{
			删除边(u, v)if (indegree(v) == 0)
				q.push(v);
		}
	}
	if (图G还有边存在)
		return 存在环
	else
		return list;

DFS:

L ← 用于存放排序结果的数组
S ← 出度为0的顶点的集合
for (S中的每个顶点)
    dfs(n) 
void dfs(node n)
{
	if (!vis[n])
	{
		vis[n] = true;
		for (每一个顶点m,满足m->n)
			dfs(m);
	}
        L.push(n);
}

即拓扑排序或者图的遍历有两种方式:深度优先和广度优先

猜你喜欢

转载自blog.csdn.net/aikudexue/article/details/89684046
今日推荐