一、定义:是将一个有向无环图G的所有的顶点排成一个线性序列,使得有向图中的任意的顶点u 和 v 构成的弧<u, v>属于该图的边
集,并且使得 u 始终是出现在 v 的前面。通常这样的序列称为是拓扑序列。
注意:
只有有向无环图才可以进行拓扑排序
二、算法思想:
1.找到有向无环图中没有前驱的节点(或者说是入度为0的节点)输入;
2.然后从图中将此节点删除并且删除以该节点为尾的弧;
三、代码实现:
1、邻接矩阵存图:
算法复杂度: 时间复杂度:O(n^2) 空间复杂度:O(n^2)
适合数据较小的题目
题目节选:hdu1285
</pre><pre name="code" class="cpp"><span style="font-size:14px; "></span><pre name="code" class="cpp" style="margin-top: 4px; margin-right: 0px; margin-bottom: 4px; margin-left: 0px; background-color: rgb(240, 240, 240); ">
<pre name="code" class="cpp">#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 1000;
int vis[maxn],g[maxn][maxn];//vis标记入度,g邻接矩阵存图
void topsort(int n) {
int k=0;
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {//找入度是0的节点
if(!vis[j]) {
printf("%d%c",j,i==n ? '\n':' ');
vis[j]--;//删除入 为0的节点并打印,是入度是-1
k=j;
break;
}
}
for(int j=1; j<=n; j++) { //找到以该点为尾的边并且删掉从新找入度为0的节点,重复过程
if(g[k][j]==1) {
g[k][j]=0;
vis[j]--; //入度更新为-1
}
}
}
}
int main() {
int n,m;
while(~scanf("%d%d",&n,&m)) {
int x,y;
memset(vis,0,sizeof(vis));
memset(g,0,sizeof(g));
for(int i=1; i<=m; i++) {
scanf("%d%d",&x,&y);
if(!g[x][y]) {
g[x][y]=1;
vis[y]++;
}
}
topsort(n);
}
return 0;
}
2、STL和优先队列
算法复杂度
时间复杂度:O(V+E)
空间复杂度:O(V)
适合数据量稍大的题目
题目引入:
Description
针对计算机系本科课程,根据课程之间的依赖关系(如离散数学应在数据结构之前开设)制定课程安排计划。
Input
第一行为样例组数T。每组样例第一行为课程数量n(1 <= n <= 5000),以下n行每行表示一门课程名称。接下来为关系数量m(1 <= m <= 10000),每一行有两个课程名称a、b,表示a课程要开设在b课程前面。(输入保证无环)
Output
每组样例第一行见输出,以下n行每行输出一个课程名称,描述拓扑排序后的课程表。如果课程优先级相同,则优先输出课程名称字典序小的课程。
Sample Input
16MathChineseEnglishSportsMusicComputer4Chinese EnglishEnglish ComputerMath ComputerMusic Computer
Sample Output
Case 1:ChineseEnglishMathMusicComputerSports
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 5000 + 5;
map <string,int> mp;
vector <int> v[maxn];
string s[maxn];
int vis[maxn],n,m;
int main()
{
int t,k=0;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
v[i].clear();
mp.clear();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
cin >>s[i];
}
sort(s+1,s+n+1);
for(int i=1;i<=n;i++)
mp[s[i]]=i;
scanf("%d",&m);
for(int i=0;i<m;i++)
{
string s1,s2;
cin >>s1>>s2;
int t1 = mp[s1];
int t2 = mp[s2];
v[t1].push_back(t2);
vis[t2]++;
}
printf("Case %d:\n",++k);
priority_queue < int,vector<int>,greater<int> > q;
for(int i=1;i<=n;i++)
{
if(!vis[i]) //入度为0就入队
q.push(i);
}
while(!q.empty()) //bfs遍历入度为0的所有的节点
{
int x = q.top();
q.pop();
printf("%s\n",s[x].c_str());
for(int i=0;i<v[x].size();i++) //与节点x相邻的节点
{
int t = v[x][i]; //以节点x为尾的边
vis[t]--; //删除该边
if(!vis[t]) //再将更新后的图的入度为0的节点入队
q.push(v[x][i]);
}
}
}
return 0;
}