题目:
5:拓扑排序
查看 提交 统计 提问
总时间限制: 10000ms 内存限制: 1000kB
描述
给出一个图的结构,输出其拓扑排序序列,要求在同等条件下,编号小的顶点在前
输入
若干行整数,第一行有2个数,分别为顶点数v和弧数a,接下来有a行,每一行有2个数,分别是该条弧所关联的两个顶点编号
输出
若干个空格隔开的顶点构成的序列(用小写字母)
样例输入
6 8
1 2
1 3
1 4
3 2
3 5
4 5
6 4
6 5
样例输出
v1 v3 v2 v6 v4 v5
1.拓扑排序的一般算法
2.关于此题
此题稍微做了一点限制,即每次输出时必须选择标号最小的入度为0的顶点。当然,拓扑排序算法本身并没有作要求,输出时随便选择一个入度为0的顶点即可。这里我采用了最小堆数据结构,使输出最小标号顶点的时间复杂度为O(logN)。
代码清单:
//TopoSort拓扑排序 //矩阵的存储结构用邻接表(Adjacency List) //维护一个最小堆,用于获得入度为0的顶点的最小标号 #include <cstdio> #include <iostream> using namespace std; #define MAXN 1000 //最大顶点数限制为999 int inDegreeList[MAXN]; //顶点的入度表 int adjList[MAXN][MAXN]; //邻接表 int minHeap[MAXN]; //最小堆 void siftup(int position) //最小堆的siftup操作 { int child=position; int father=(child-1)/2; int temp=minHeap[child]; //挖坑 while (father>=0 && child>=1) { if (minHeap[father]>temp) //坑往上升 { minHeap[child]=minHeap[father]; //father降了下来,child假装升了上去(下一次还用temp比较就是) child=father; father=(child-1)/2; } else break; } minHeap[child]=temp; //填坑 } void siftdown(int position, int heapsize) //最小堆的siftdown操作 { int father=position; int child=father+father+1; //确切而言是左儿子 int temp=minHeap[father]; //挖坑 while (child<heapsize) { if (child+1<heapsize && minHeap[child]>minHeap[child+1]) //把两个儿子较小的那一个 child=child+1; if(temp>minHeap[child]) //坑往下降 { minHeap[father]=minHeap[child]; father=child; child=father+father+1; } else break; } minHeap[father]=temp; //填坑 } void heapInsert(int e, int *heapSize) { minHeap[*heapSize]=e; siftup(*heapSize); ++(*heapSize); } int heapRemove(int *heapSize) { int _min=minHeap[0]; //最小的元素暂存 minHeap[0]=minHeap[*heapSize-1]; //把最后一个元素移到最小元素的位置 --(*heapSize); siftdown(0, *heapSize); //堆内用siftdown调整 return _min; } int main() { //freopen("D:\\in.txt", "r", stdin); //freopen("D:\\out.txt", "w", stdout); int n, m, from, to, heapSz=0, ov, ovCount=0; scanf("%d", &n); scanf("%d", &m); for (int i=0; i<n+1; ++i) inDegreeList[i]=0; //入度表被初始化为全0 for (int i=0; i<n+1; ++i) { adjList[i][0]=1; //每行的第0个元素用于记录下一个邻接边终点存放的位置 for (int j=1; j<n+1; ++j) { adjList[i][j]=-1; //初始没有任何邻接边终点放入,全部置为-1 } } for (int i=0; i<m; ++i) //设置入度表和邻接表 { scanf("%d%d", &from, &to); ++inDegreeList[to]; //顶点入度+1 adjList[from][adjList[from][0]]=to; //设置邻接表 ++adjList[from][0]; } //真正开始TopoSort算法 //入度表中入度为0的顶点全部进堆 for (int i=1; i<n+1; ++i) { if (inDegreeList[i]==0) { heapInsert(i, &heapSz); } } while (ovCount<n) { ov=heapRemove(&heapSz); //入度为0的最小顶点编号出堆 ++ovCount; //ov邻接边的终点的入度都-1 for (int i=1; adjList[ov][i]!=-1; ++i) { int temp=adjList[ov][i]; --inDegreeList[temp]; if (inDegreeList[temp]==0) //入度减为0,插入最小堆 { heapInsert(temp, &heapSz); } } //输出 printf("v%d ", ov); } return 0; }