拓扑排序和欧拉路
拓扑排序
简介
拓扑排序是指,在有向无环图(DAG)中,总有节点A指向节点B的这一关系,这可以理解为节点A的优先级高于节点B。而拓扑排序需要的就是把节点按优先级排序。
这需要用到两个概念:出度和入度。出度即节点A指向多少个节点,入度即节点A被多少个节点所指。显然,出度为0时,优先级最低,入度为0时优先级最高
那么如何输出一个拓扑排序呢?只需要我们找到所有入度为0的点,将其输出,再继续输出其下层的点,重复此步骤即可,这是天然符合BFS的。
接下来让我们看看用BFS和DFS实现拓扑排序的方法。
P1113 杂务
这个题可以通过DFS加记忆化搜索去做,即完成一项任务的最小时间取决于其所有前驱中花费时间的最大值,在图论基础中有涉及。
但此题也可通过先获得拓扑序,对拓扑序分层后使用动态规划求解
在此提供BFS+DP的代码,需要注意两个点。
- 其一是拓扑排序的只会把入度为0的点入队。除去一开始为0的点,只有入度被改变的点才可能为0,所以不需要重新检查一次
- 其二是需要有dp检查最大值,因此问题是一个最长路问题,需要用dp去储存当访问到此处时的最长路劲。
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
using namespace std;
const int MAXN = 1e4+5;
int n;
vector<int> a[MAXN];
int times[MAXN],dp[MAXN],rudu[MAXN];
int res=0;
deque<int> q;
void func(){
q.clear();
for(int i=1;i<=n;i++){
if(rudu[i]==0){
q.push_back(i);
dp[i] = times[i];
}
}
while(q.size()){
int nowIndex = q.front();
q.pop_front();
for(int i=0;i<a[nowIndex].size();i++){
int t = a[nowIndex][i];//a的邻居
rudu[t]--;
if(rudu[t]==0) q.push_back(t);
dp[t] = max(dp[t],dp[nowIndex]+times[t]);
}
res = max(dp[nowIndex],res);
}
}
int main() {
cin>>n;
for(int i=1;i<=n;i++){
int a1,b,c;cin>>a1>>b>>c;
times[i]=b;
while(c!=0){
rudu[i]++;
a[c].push_back(i);
cin>>c;
}
}
func();
cout<<res;
return 0;
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 羊习习在学习!