ACM-图论-拓扑排序
来源:互联网 发布:辛翠英诊所网络预约 编辑:程序博客网 时间:2024/04/28 02:04
拓扑排序用于解决图论中有向图的一类序列问题。即在某一个有向图graph中,假设每一条有向边(u,v)代表节点u必须排在节点v的前面,那么按照这样的规则,将所有的节点进行排序,最终得出的序列就称为拓扑序。拓扑排序在ACM比赛和实际生活中都比较常见,只要能将事物抽象成有向图,并要求按规则排序,那么就可以考虑拓扑排序,比如选修课程的安排、按胜负排名次等。
拓扑排序只适用于有向无环图,所以使用拓扑排序的第一步就是先将问题抽象成有向图,进行图的初始化、建立等工作,然后运行拓扑排序算法即可。
然后考虑如何实现拓扑排序。按照其原始的定义,边(u,v)代表u排在v前面,也就是说没有边指向的节点拓扑序较小,所以拓扑序为1的节点应该是入度为0的点,再考虑拓扑序为2的节点,它最多只应该是拓扑序唯一指向的节点,而不能由其它节点指向它,否则它的拓扑序不为2,那这样看来该节点不就是删除以拓扑序为1的节点出发的边后,入度为0的节点了么。综上,拓扑排序算法的大题思路就是:每次选出入度为0的节点,然后删除该节点以及由该节点出发的边,调整其它节点的入度,然后再选出入度为0的节点,相同的处理方法,依次类推,直到没有入度为0的节点为止。那么,每次选出节点的顺序就是拓扑序。
......
最后考虑一下细节,如果图用邻接表来存储的话,那么入度信息就可以使用第一个元素维护,并且重边对拓扑序无影响,因为删除节点的时候同样会删除重边,还有就是拓扑排序运行的最终结果就是为每一个节点都分配了拓扑序号,所有节点维护的入度信息都被更新为了0,否则说明图中存在环。
这里有一道关于拓扑排序的常见应用的题,HDOJ:1285,时空转移(点击打开链接),题目如下:
确定比赛名次
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 16595 Accepted Submission(s): 6566
其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。
4 31 22 34 3
1 2 4 3
给出比赛的输赢结果,要求赢得排在输的前面,然后要求以此对所有的队伍进行排序。
分析:
可以讲队伍看成节点,然后将输赢看成节点间的一条边,这样就将问题抽象成了图,那么问题就转化成了拓扑排序。
源代码:
#include <cstdio>#include <vector>#include <queue>#include <algorithm>using namespace std;const int MAXN = 505;vector<int> Graph[MAXN];int TopNum[MAXN], NodeNum[MAXN];;int NumVertex, NumEdge;// 有向无环图一定存在拓扑序void TopSort(){ // 维护入度为0的节点,编号从小到大排序,保证编号小的节点的拓扑序小 priority_queue<int, vector<int>, greater<int> > que; // 将入度为0的节点加入队列 for(int i=1; i<=NumVertex; ++i) { if(Graph[i][0] == 0) que.push(i); } // 循环处理入度为0的节点,并赋予拓扑序 int cnt = 0; while(!que.empty()) { int u = que.top(); que.pop(); // 将最较小拓扑序号赋给入度为0且当前编号最小的节点 TopNum[u] = ++cnt; // 删除节点u出发的边,并调整其它节点的入度 for(int i=1; i<Graph[u].size(); ++i) { // 将调整后入度为0的节点加入队列 if(--Graph[Graph[u][i]][0] == 0) que.push(Graph[u][i]); } } // 图中存在环则无拓扑序 if(cnt != NumVertex) return; // 如果图并不一定是全联通的,那么判原图的某一连通域中是否存在环: for(int i=1; i<=NumVertex; ++i) if(Graph[i][0]) puts("somerwhere of the graph has a cycle"); // 输出以拓扑序排列的节点编号 for(int i=1; i<=NumVertex; ++i) NodeNum[TopNum[i]] = i; for(int i=1; i<=NumVertex; ++i) printf("%d%c", NodeNum[i], i==NumVertex?'\n':' ');}int main(){//freopen("sample.txt", "r", stdin); while(~scanf("%d%d", &NumVertex, &NumEdge)) { // 初始化 for(int i=1; i<=NumVertex; ++i) { Graph[i].clear(); // 初始化入度 Graph[i].push_back(0); } // 建图 for(int i=1; i<=NumEdge; ++i) { int u, v; scanf("%d%d", &u, &v); // 使用邻接表时,重边对于拓扑序无影响,所以可以不用处理 //if(find(Graph[u].begin(), Graph[u].end(), v) // == Graph[u].end()) { Graph[u].push_back(v); // v节点的入度加1 ++Graph[v][0]; } } // 拓扑排序 TopSort(); } return 0;}
其它相关的题目还有,HDOJ:1811,UESTC:1150。
- ACM-图论-拓扑排序
- 拓扑排序 gdufe acm 1183
- ACM 104. [NOIP2003] 神经网络(拓扑排序)
- 拓扑排序(图论)
- poj3687 图论 拓扑排序
- 图论 拓扑排序
- 图论1拓扑排序
- 图论:拓扑排序
- 拓扑排序-图论
- 图论:拓扑排序
- 【图论】拓扑排序
- C++ 图论-拓扑排序
- 杭电ACM 1285 确定比赛名次(拓扑排序)
- [ACM] hdu 1285 确定比赛名次 (拓扑排序)
- [ACM] hdu 3342 Legal or Not (拓扑排序)
- [ACM] POJ 1094 Sorting It All Out (拓扑排序)
- ACM知识竞赛 之 SDUT3037 让领导先走(拓扑排序)
- ACM 模板--邻接表 有向图 拓扑排序
- VMware虚拟机Mac系统怎么切换中英文输入法?
- MemSolid2.0:PCIe SSD高温保护技术详解
- 《转》qt中添加背景图片(stylesheet)
- plsql dev查询偶尔卡死,Windows上如何禁用TCP/IP自动调优特性
- 使用plupload进行多文件上传
- ACM-图论-拓扑排序
- C# notifyIcon
- 音视频该怎么学?
- Servlet和JSP
- [折半枚举] poj 2785 4 Values whose Sum is 0
- android 锁屏音乐控制
- android 不能试用switch
- 67 - 机器人的移动范围
- VMware Workstation克隆CentOS 没有网卡eth0 无法开启网络服务