拓扑排序

来源:互联网 发布:邮件服务器 知乎 编辑:程序博客网 时间:2024/05/30 22:53

    今天,跟同学在NYOJ上做了一道搜索题,原先一直是以错误的思路来思考该问题。最后,问了别的同学后才知道原来是拓扑排序这个高级货。

  按照白书上所介绍的拓扑排序是有一下定义:

  假设有n个变量,还有m个二元组(u,v),分别表示变量u小于v。那么,所有变量从小到大排列起来应该是什么样子的呢?例如有4个变量a,b,c,d,若以知a<b,c<d,d<c,则这4个变量的排序可能是a<d<c<b。尽管还有可能其他的可能,你只需找出其中的一个即可。

  分析:

     把每个变量看成一个点,“小于”关系看成有向边,则我们得到了一个有向图。这样,我们的任务实际上是把一个图的所有结点排序,使得每一条有向边(u,v)对应的u都排在v的前面。在图论中,这个问题称为拓扑排序

  不难发现:如果图中存在有向环,则不存在拓扑排序,反之则存在。我们把不包含有有向环的有向图称为有向无环图。可以借助dfs函数完成拓扑排序:在访问完一个结点之后把它加入到当前拓扑序的首部(想想为什么不是尾部)

    (哈哈,个人见解是因为当dfs搜索时是先搜索到儿子结点的,所以先加入topo数组的是儿子结点,可以结合后面的程序加以理解)

 

 

const int MAXN = SIZEOF;int t,n;int c[MAXN];int topo[MAXN],G[MAXN][MAXN];bool DFS(int u){    c[u] = -1;                    //正在栈中    for(int v = 0;v < n;v++)if(G[u][v])    {        if(c[v]<0)return false;   //存在有向环,失败退出        else if(!c[v] && !dfs(v))return false;    }    c[u] = 1;topo[--t] = u;    return true;}bool TopoSort(){    t = n;    memset(c,0,sizeof(c));    for(int v = 0;v < n;v++)if(!c[v])      if(!DFS(v))return false;    return true;}

 

    这里用到了一个c数组,c[u] = 0表示从来没有访问过(从来没有调用过dfs(u);c[u]=1表示已经访问过,并且还递归的访问过它的所有孙子(即dfs(u)曾被调用过,并已返回));c[u]=-1表示正在访问(即递归调用dfs(u)正在栈帧里,尚未返回)。     

   有向环:G[1][3],G[3][1],G[1][1]等都称为有向环

HDU 确定比赛名次

最简单的拓扑排序,数目很小,直接用矩阵。后来做的题发现有很多都不能用矩阵表示,要用邻接表或者链表来表示,主要是先找deg[i]为0的,他就排在前面,然后以他为起点,跟他连接的点的deg[]--,如此下去,排名是按分数优先,分数相同的按字典顺序排,先贴这道题的代码。

#include <stdio.h>#include <string.h>const int MAX = 502;int n,m;int topo[MAX],degree[MAX],G[MAX][MAX];void TopoSort(){    int p = -1;    for(int i = 1;i <= n;i++)    {        for(int j = 1;j <= n;j++)if(!degree[j])        {            topo[i] = p = j;            degree[j]--;            break;        }        for(int j = 1;j <= n;j++)if(G[p][j])        {            G[p][j] = 0;            degree[j]--;        }    }}void Print(){    for(int i = 1;i < n;i++)      printf("%d ",topo[i]);    printf("%d\n",topo[n]);}int main(){    while(~scanf("%d%d",&n,&m))    {        int x,y;        memset(G,0,sizeof(G));        memset(degree,0,sizeof(degree));        for(int i = 0;i < m;i++)        {            scanf("%d%d",&x,&y);            if(!G[x][y])            {                G[x][y] = 1;                degree[y]++;            }        }        TopoSort();        Print();    }    return 0;}


 

 

原创粉丝点击