拓扑排序
来源:互联网 发布:邮件服务器 知乎 编辑:程序博客网 时间: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;}
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 【拓扑排序】
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- nohup命令
- zoj 2526
- apache和tomcat区别
- ExtJS 中 store 的使用经验
- ClassLoader原理
- 拓扑排序
- 移植ucgui到ucosii--part1
- exe4j将jar文件生成exe可执行文件
- int 13h 参数大全
- 改变一个apk的packagename的简单流程,就2个步骤
- 移植ucgui到ucosii--part2
- 一个危险的XSS案例——轻松拿到登录用户的cookie
- web.xml配置详解
- 进程通信:管道(pipe)和socketpair区别