題目:
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;
}