拓扑排序

拓扑排序

  对一个集合进行拓扑排序,相当于由这个集合上的偏序关系生成一个全序关系,满足偏序关系中较小的一个排在较大的一个之前。在有向图中,表示为:对于图中每条有向边$;(u,v);$,顶点序列$A$满足$;u;$出现在$;v;$之前,序列$A$即为拓扑序,得到序列$A$的过程即为拓扑排序。
  比如需要完成一些任务,每个任务都有一些准备任务,只有当准备任务完成之后才可以去做该任务。符合要求的任务完成序列就是对应的拓扑序。

做法

  (1) 对于每对偏序关系建边。
  (2) 找出所有入度为$;0;$的顶点,加入到队列中。
  (3) 取出队头顶点$;v;$,扫描所有出边,对于所有与顶点$;v;$关联的点入度减一,即删除所有出边。如果有顶点入度被减为一,则将这个顶点加入到队列中去。
  (4) 当队列不空时,重复步骤(3)。

板子题

  大意:给出一些任务及其准备任务的编号以及每项任务所需时间,求在可以同时并行处理多项任务情况下的最少耗时。
  做法:在拓扑排序中,由准备工作的完成时刻递推出当前任务的完成时刻,最后取每项任务完成时刻的最大值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

#include <iostream>

using namespace std;

const int N = 10000 + 10;
const int M = 10000000 + 10;

int nxt[M], hd[N], to[M];
int ent[N];
int ans[N];
int len[N];

int cnt;
int res;
int n;

inline int (int a, int b)
{
return a > b ? a : b;
}

inline void add(int x, int y)
{
to[++cnt] = y;
nxt[cnt] = hd[x];
hd[x] = cnt;
ent[y]++;
}

queue<int> q;

void xhl()
{
for (int i = 1; i <= n; i++)
{
if (ent[i] == 0)
{
q.push(i);
ans[i] = len[i];
}
}
while (q.size())
{
int tp = q.front();
q.pop();
for (int i = hd[tp]; i; i = nxt[i])
{
int x = to[i];
ent[x]--;
ans[x] = Max(ans[x], ans[tp] + len[x]);
if (ent[x] == 0)
{
q.push(x);
}
}
}
}

int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
int id;
cin >> id >> len[i];
int ver;
while (cin >> ver, ver)
{
add(i, ver);
}
}
xhl();
for (int i = 1; i <= n; i++)
{
res = Max(res, ans[i]);
}
cout << res << endl;
}

  $largetext{原题传送门}$