【拓扑排序】
【拓扑排序】
概念
每个节点的前置节点都在当前节点之前
要求 有向无环图
拓扑排序顺序可能不止一种
拓扑排序也可判断有无环
求拓扑序
(1)图中找到所有入度为0的点
(2)把所有入度为0的点在图中删掉,然后删掉影响
(3)直到所有点都没删掉->依次删除的顺序就是拓扑排序结果
(4)无法删掉所有点->有环
【伪代码】
queue<-所有入度为0的点
while(queue不空){
t<-队头
枚举t的所有出边 t->j
删掉t->j,d[j]--
if(d[j]==0)
queue<-j
}
板子题
https://www.luogu.com.cn/problem/B3644
模版代码
const int N=110;
int n;
vector<int> g[N];
void solve(){
cin>>n;
vector<int> du(n+1,0);
for(int i=1;i<=n;i++){
while(1){
int son;
cin>>son;
if(son==0) break;
else{
g[i].push_back(son);
du[son]++;
}
}
}
queue<int> q;
for(int i=1;i<=n;i++){
if(du[i]==0){
q.push(i);
}
}
while(q.size()){
int t=q.front();
q.pop();
cout<<t<<" ";
for(auto son:g[t]){
du[son]--;
if(du[son]==0){
q.push(son);
}
}
}
}
字典序最小的拓扑序
https://www.luogu.com.cn/problem/U107394
把队列换成小根堆即可
const int N=1e5+10;
int n,m;
vector<int> g[N];
set<PII> edg;
void solve(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
edg.insert({u,v});
}
vector<int> du(n+1,0);
for(auto [u,v]:edg){
//cout<<u<<" "<<v<<endl;
g[u].push_back(v);
du[v]++;
}
priority_queue<int,vector<int>,greater<int>> q;
for(int i=1;i<=n;i++){
if(du[i]==0){
q.push(i);
}
}
while(q.size()){
int t=q.top();
q.pop();
cout<<t<<" ";//以弹出序列为拓扑序
for(auto son:g[t]){
du[son]--;
if(!du[son]){
q.push(son);
}
}
}
}