【拓扑排序】

【拓扑排序】

概念

每个节点的前置节点都在当前节点之前

要求 有向无环图

拓扑排序顺序可能不止一种

拓扑排序也可判断有无环

求拓扑序

(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);
            }
        }
    }
}
posted @ 2025-07-01 21:05  White_ink  阅读(4)  评论(0)    收藏  举报