拓扑排序
转载自: https://blog.csdn.net/y_universe/article/details/79342940
定义
对一个有向无环图(Directed Acyclic Graph简称DAG) G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
在AOV网中,若不存在回路,则所有活动可排列成一个线性序列,使得每个活动的所有前驱活动都排在该活动的前面,我们把此序列叫做拓扑序列(Topological order),由AOV网构造拓扑序列的过程叫做拓扑排序(Topological sort)。AOV网的拓扑序列不是唯一的,满足上述定义的任一线性序列都称作它的拓扑序列。
换句话说: 在实践的解题中,多用于求解具有严格顺序要求的活动及这个活动所耗费的时间。如要完成B活动,首先要完成A活动才行,也就是说只有A活动完成了才能做B活动。具体见后面例题解析。
拓扑排序的实现步骤
1. 从图中选择一个没有前驱(即入度为0)的顶点并输出。
2. 删除该顶点和所有以它为起点的有向边。
重复 1 和 2 直到当前的图为空或当前图中不存在无前驱的顶点为止。若当前图中不存在无前驱的顶点说明有向图中必存在环。(ps:存在环的情况也就是题目中无解的情况)
例题1:最短工期 (25分)
输入样例 1:
9 12
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
5 4 0
4 6 9
4 7 7
5 7 4
6 8 2
7 8 4
输出样例 1:
18
输入样例 2:
4 5
0 1 1
0 2 2
2 1 3
1 3 4
3 2 5
输出样例 2:
Impossible
解析:
就如题目所说的,一个项目的任务也是有先后依赖关系的,也就是说是有严格的顺序执行的。这里就可以用到拓扑排序,只是这里不是求任务完成顺序,而是最早完工时间。
具体解析见AC代码:
#include<bits/stdc++.h>
using namespace std;
int dis[105][105],ru[105],f[105];
int n,ans,cnt=0;
void topological_sort(){
while(1){
int flag=0;
for(int i=0;i<n;i++){
if(!ru[i]){ //入度为0的顶点(即没有前驱任务的任务,那么这个任务就可以做了)
ru[i]--;//变为-1,也就是这个任务做完了,后面不用考虑了
cnt++;
flag=1;
for(int j=0; j<n; j++){
if(dis[i][j]!=-1){//存在以i为前驱任务的任务
ru[j]--; // 入度减一(把i任务去掉了,则j的前驱任务少了一个)
f[j]=max(f[j],f[i]+dis[i][j]); //选择最长的工作时间
ans=max(ans,f[j]);//统计最早完工时间
}
}
}
}
if(!flag) break; //不存在入度为0的点,跳出循环
}
if(cnt==n) cout<<ans<<endl; //全部顶点和边成功去掉
else cout<<"Impossible"<<endl;//存在环
}
int main(){
int m, p, x, y;
cin>>n>>m;
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
dis[i][j]=-1;//初始边的权都为-1,因为工作时长可能是0,所以初始dis都赋值为-1
while(m--){
cin>>x>>y>>p;
dis[x][y]=p;
ru[y]++;//ru[y]顶点y的入度,(即题目中的y任务的前驱任务们)
}
topological_sort(); //拓扑排序
return 0;
}
优化:
用vector,queue优化的算法,多用于只求活动执行的顺序,不需要求权值
void topological_sort(){
queue<int>q;
vector<int>edge[n];
for(int i=0;i<n;i++) //n:结点的总数
if(in[i]==0) q.push(i); //将入度为0的点入队列
vector<int>ans; //ans 为拓扑序列
while(!q.empty())
{
int p=q.front(); q.pop(); // 选一个入度为0的点,出队列
ans.push_back(p);
for(int i=0;i<edge[p].size();i++)
{
int y=edge[p][i];
in[y]--;
if(in[y]==0) q.push(y);
}
}
if(ans.size()==n){
for(int i=0;i<ans.size();i++)
cout<<ans[i]<<" ";
}else cout<<"No Answer!\n"; // ans中的长度与n不相等,存在环
}
推荐题目:https://acm.zcmu.edu.cn/JudgeOnline/problem.php?id=2153
推荐博客:https://blog.csdn.net/qq_41713256/article/details/80805338
欢迎大家批评改正!!!