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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章