简单介绍:
由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。离散数学中关于偏序和全序的定义:
若集合X上的关系是R,且R是自反的、反对称的和传递的,则称R是集合X上的偏序关系。
设R是集合X上的偏序(Partial Order),如果对每个x,y属于X必有xRy 或 yRx,则称R是集合X上的全序关系。
比较简单的理解:偏序是指集合中只有部分成员可以比较,全序是指集合中所有的成员之间均可以比较。
注意:
①若将图中顶点按拓扑次序排成一行,则图中所有的有向边均是从左指向右的。
②若图中存在有向环,则不可能使顶点满足拓扑次序。
③一个DAG的拓扑序列通常表示某种方案切实可行。
实现过程:
1.在有向图中选一个没有前驱的顶点并且输出
2.从图中删除该定点和所有出边
3.重复上述两步直至所有顶点输出,或者当前图中不存在无前驱的顶点为止,后者代表我们的有向图是有环的,因此也可以通过拓扑排序来判断一个图是否有环。
1.什么是拓扑排序
百度解释:由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
我们可以简单的理解为,做一件事情前是要有先决条件的,比如,你吃饭的前提是要先做饭。睡觉的前提是A完题(.疯狂暗示)

如图此时没有先决条件的仅有1,所以可以将其移除
得到如图结果此时2无先决条件再将2移除,依次操作。



所以按照以上步骤,我们可以看到拓扑排序,就是按照先决条件的排序。而且如图所示。排序结果也不一定是唯一的,到3 4时均无先觉条件均可以输出。结果可能为1 2 3 4 5或1 2 4 3 5.
那怎样可以让他按最小字典序输出呢 方法:优先队列。
2.例题陈列(由易到难)
1.入门题
(3)HDU 1285 确定比赛名次
(4)HDU 3342 Legal or Not
(5)Uva 10305 Ordering Tasks 【easy】
2.上升题
(1) POJ 3660 Cow Contest
(2)POJ 3553 Task schedule
(3)POJ 3687 Labeling Balls
(4)2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 Skiing
3.苦难题
(1)Codeforces 512A Fox And Names
(2)Codeforces 516B Drazil and Tiles
(3)Codeforces 698B Fix a Tree
(4)HDU 3231 Box Relations
(5)SDNU 1031 字母排序
3.例题讲解
(1)入门题目
题目简介:选课的拓扑排序,入门题目。判断有无环产生。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100100;
vector <int> G[maxn];
int grath[maxn], t, n, m;
void tosort()
{
queue <int> que;
int sum = 0;
for(int i = 1; i <= n; i++) if(!grath[i]) que.push(i);
while(!que.empty())
{
int a = que.front(); que.pop();
sum++;
for(int i = 0; i < G[a].size(); i++)
{
if(!(--grath[G[a][i]])) que.push(G[a][i]);
}
}
if(sum == n) // 无环,所有点都拆下来了
printf("Correct\n");
else
printf("Wrong\n");
}
int main()
{
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &n, &m);
memset(grath, 0, sizeof(grath));
for(int i = 0; i <= n; i++) G[i].clear();
for(int i = 0; i < m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
G[a].push_back(b);
grath[b]++;
}
tosort();
}
return 0;
}
题目简介:对拓扑排序加强的理解,病毒数的传播,
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100010;
const int mod = 142857;
int n, m, k, grath[maxn], t[maxn], d;
vector <int> G[maxn];
void tosort()
{
int sum = 0;
queue <int> que;
for(int i = 1; i <= n; i++) if(!grath[i]) que.push(i);
while(!que.empty())
{
int a = que.front(); que.pop();
sum = (sum + t[a]) % mod;
for(int i = 0; i < G[a].size(); i++)
{
t[G[a][i]] = (t[G[a][i]] + t[a]) % mod;
if(!(--grath[G[a][i]]))
{
que.push(G[a][i]);
}
}
}
printf("%d\n", sum % mod);
}
int main()
{
while(scanf("%d%d%d", &n, &m, &k) != EOF)
{
for(int i = 0; i <= n; i++) G[i].clear(), grath[i] = 0, t[i] = 0;
for(int i = 1; i <= k; i++) scanf("%d", &d), t[d]++;
for(int i = 0; i < m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
G[a].push_back(b);
grath[b]++;
}
tosort();
}
return 0;
}
本文深入解析拓扑排序的概念,从偏序到全序的转换,以及如何通过算法判断图中有无环,提供了一系列由易到难的例题,并附带详细代码讲解。
483

被折叠的 条评论
为什么被折叠?



