【模板】拓扑排序

拓扑排序(定义):
对于有向图的节点按照访问顺序排序,最终形成一个线性序列(该序列满足:每个顶点出现且只出现一次)
不难发现:如果图中存在有向环,则不存在拓扑排序

拓扑排序(演示)
【模板】拓扑排序_第1张图片

  • 利用深度优先搜索排序

代码参考《算法竞赛入门经典(第2版)》

int c[maxn]; //c[u]=0表示没有访问过,c[u]=1表示已经访问过,c[u]=-1表示正在访问
int topo[maxn],t; //数组模拟栈,t是顶点总数
bool dfs(int u) 
{
	c[u] = -1; //从u开始dfs,正在访问u,标记为-1
	for (int v = 0; v < n; v++) //遍历每一个顶点
	{
		if (G[u][v]) //有从u到v的指向
		{
			if (c[v] < 0) return false;//存在有向环,返回false
			if (!c[v] && !dfs(v)) return false;// 如果「未搜索」那么搜索相邻节点,但如果搜索后发现有环,返回false
		}
	}
	//如果前面都没有返回,说明从u开始的有向图没有环
	//访问标志设为1
	//在访问完一个节点之后把它加到当前拓扑排序的首部
	//从u开始的dfs,生成一个u在首部的topo数组(此时的topo数组不一定包括所有节点,因此toposort()函数仍然需要遍历所有节点)
	c[u] = 1; topo[--t] = u; 
	return true;
}
bool toposort()
{
	t = n;
	memset(c, 0, sizeof(c));
	for (int u = 0; u < n; u++)//每次挑选一个「未搜索」的节点,开始进行深度优先搜索(考虑到有些节点是独立的)
	{
		if (!c[u])
		{
			if (!dfs(u)) return false;
		}
	}
	return true;
}
  • 利用广度优先搜索排序

不难理解,将入度为0的顶点压入队列,该顶点指向的顶点的度数-1
代码参考:拓扑排序入门(真的很简单)

    queue<int>q;
    vector<int>edge[n];
    for(int i=0;i<n;i++)  //n  节点的总数
        if(in[i]==0) q.push(i);  //将入度为0的点入队列
    vector<int>ans;   //ans 为拓扑序列
    while(!q.empty())
    {
        int p=q.front(); q.pop(); // 选一个入度为0的点,出队列
        ans.push_back(p); //压入拓扑序列
        for(int i=0;i<edge[p].size();i++)
        {
            int y=edge[p][i];
            in[y]--;
            if(in[y]==0)
                q.push(y);  
        }
    }
    if(ans.size()==n)   
    {
        for(int i=0;i<ans.size();i++)
            printf( "%d ",ans[i] );
        printf("\n");
    }
    else printf("No Answer!\n"); //  ans 中的长度与n不相等,就说明无拓扑序列

你可能感兴趣的:(【模板】拓扑排序)