【算法专题】拓扑排序入门

拓扑排序

介绍

对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。
通俗讲就是按照若干个a必须在b前这样的规则将一组数据排序
我觉得拓扑排序是一种结果而不是一个过程。他不想冒牌排序、选择排序那种直接给出了排序的操作步骤,拓扑排序只是给出了排序的结果(对排序的要求),并没有给出排序的操作步骤。
可以使用拓扑排序来判断图中有没有环

拓扑排序的方法

方法一:使用最简单的dfs实现

每次搜索到出度为0的点返回,便返回边输出;

#include <iostream>
#include <vector>
using namespace std;

const int MAXSIZE = 1e2 + 5;

int vis[MAXSIZE];  //储存每个点个访问状态,  0 表示未访问  -1 表示正在访问  1表示 已访问过
int topo[MAXSIZE];   //储存排序的结果。
vector<int> G[MAXSIZE];  //储存拓扑关系

int n,m,t;

bool toposoft(int u)
{
    vis[u] = -1;   // 标记当前点正在访问
    for(auto v:G[u])   // 遍历当前点u的每个可到达点
    {
        if(vis[v] == -1) return false;  // 如果下一个已经访问过说明此图存在环。
        if(!vis[v]) toposoft(v);  
    }
    vis[u] = 1;
    topo[t--] = u;  // 逆序保存,就能正序输出拓扑序了
}

int main()
{
    //读入数据
    /*
    	拓扑关系的储存;  对于输入的每组a,b;   a->b;
    	G[a].emplace_back(b);
    */
    t = n;
    for(int i=1;i<=n;i++) if(!vis[i]) toposoft(i);
    
    return 0;
}

方法二:使用队列或者优先队列实现

优先队列可以保证输出的结果是字典序最小或最大之类的.
如果题目没有要求(输出任意一组符合题意的就行) 那么用普通队列就可以

思路就是将所有入度为0的点放入队列中, 每次取出队首元素将该元素的所有相邻节点入度减一,如果入读变成了零就放入队列,重复操作直到队列为空.

#include <iostream>
#include <cstring>
#include <queue>
#include <vector>

using std::vector;
using std::greater;
using std::priority_queue;

const int MAXSIZE = 500 + 5;

int indegree[MAXSIZE];
priority_queue<int,vector<int>,greater<int>> pq;
int G[MAXSIZE][MAXSIZE];
int n,m,x,y;

void toposoft()
{
    while(!pq.empty()) pq.pop();
    int top;
    for(int i=1;i<=n;i++)
    {
        if(indegree[i] == 0) pq.push(i);
    }
    bool flag = true;
    while(!pq.empty())
    {
        top = pq.top();
        pq.pop();

        indegree[top] = -1;

        if(flag)
        {   
            printf("%d",top);
            flag = false;
        }else printf(" %d",top);

        for(int i=1;i<=n;i++)
        {
            if(G[top][i])
            {
                indegree[i]--;
                if(indegree[i] == 0) pq.push(i);
            }
        }
    }
    printf("\n");
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(G,0,sizeof(G));
        memset(indegree,0,sizeof(indegree));
        if(m+n == 0) break;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&x,&y);
            if(G[x][y] == 0)
            {
                G[x][y] = 1;
                indegree[y]++;
            }
        }
        toposoft();
    }
    return 0;    
}

猜你喜欢

转载自blog.csdn.net/qq_30445397/article/details/107577708
今日推荐