有向无环图DAG 常用来表示事件之间的依赖关系,任务之间的调度
典型:依赖处理
拓扑排序就是把DAG转变为一个数列
在图论上,他是把DAG生成一个线性数列,表示这个图顶点之间的先后关系
过程
- 建立一个空队列,把所有入度为 0 的加入队列
- 然后从队列中取出一个节点,把该节点所有的出边删除,即入度 -1, 再判断该边通向的节点是否已经没有边连入(即入度是否为 0 ),若是,加入队列
- 重复,直到队列中不剩下任何节点
注:拓扑排序是对于DAG而言。如果需要判断图中是否存在环, 可以统计是否所有的节点都入过队。存在未入队的节点,代表存在环(无法拓扑排序) (因为入度不可能为0)
#include <cstdio>
#include <algorithm>
#define MAXN 1111
#define MAXM 121111
int n, m, cnt;
int head[MAXN], q[MAXN], ru[MAXN];
struct edge {
int y, next;
}e[MAXM];
void add_edge(int x, int y) {
e[++cnt].y = y;
e[cnt].next = head[x];
head[x] = cnt;
return ;
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i++) {
int x, y;
scanf("%d%d", &x, &y);
ru[y]++;
add_edge(x, y);
}
int l = 1, r = 0;
for(int i = 1; i <= n; i++) {//入队
if(!ru[i]) {
r++;
q[r] = i;
}
}
while(l <= r) {
int now = q[l];
l++;//首元素出队
for(int i = head[now]; i; i = e[i].next) {
int y = e[i].y;
ru[y]--;//终点为y的线段 入度——
if(!ru[y]) {//如果入度减到了零 ,就让它进队(从后面入)
q[++r] = y;
}
}
}
for(int i = 1; i <= m; i++) printf("%d ", q[i]);//队列前m个是已经拓扑排序好了的元素
return 0;
}
拓扑排序的作用 应用 :
可以保持无后效性,进而使用DP
注:记忆化搜索同样可以解决无后效性的问题