openjudge 拓扑排序

题目:

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;
}



你可能感兴趣的:(拓扑排序,最小堆,sorting,OpenJudge,TopoSort,Topological)