拓扑排序
定义:在一个有向图中对每一个节点进行排序,使其每一个节点都不会指向前面的节点就是拓扑排序。(根据定义很容易得到有环的话是无法进行拓扑排序的。)
由于有些节点之间并无直接联系,所以节点无法比较其大小,但知道其大致放在那个方位。
如:若有4个变量,已知a<b,c<b,d<c则四个变量的大小关系可以为a<d<c<b也可以为d<a<c<b。
拓扑排序的方法可以分为两种:
一、 kahn算法
将节点看成有向联通图
-
每一个节点都有一个入度
-
每个节点都有上(下)一个节点
起始时入度为0的节点为起始点,通过它们向下面的节点遍历(放入队列),遍历到下面的节点则删去其之间的连线(也就是下面一个节点的入度减一),若下面一个节点的入度为0的话则将其放入队列,向下遍历。直到队列中无元素为止。
遍历所有节点,若还是存在入度不为0的节点,则该连通图存在环,则不能拓扑排序,若全部为0,则按照放入队列的顺序输出节点即可。
优先队列的拓扑排序: 用于有特殊限制的拓扑排序,如:需按字典序输出,或者先输入较小的节点。
//
// Created by fallrain on 2020/8/23.
//
#include<bits/stdc++.h>
using namespace std;
int n,m;
map<int,int>mp;
vector<int>v[105];
queue<int>q;
vector<int >ans;
int main()
{
while(cin>>n>>m) {
for(int i=0;i<n;i++)
{
v[i].clear();
}
while(!q.empty())
q.pop();
ans.clear();
mp.clear();
if(n==0&&m==0)
break;
for (int i = 0; i < m; i++) {
int a, b;
cin >> a >> b;
v[a].push_back(b);
mp[b]++;
}
for (int i = 1; i <= n; i++) {
if (mp[i] == 0) {
ans.push_back(i);
q.push(i);
}
}
while (!q.empty()) {
int next = q.front();
q.pop();
for (int i = 0; i < v[next].size(); i++) {
mp[v[next][i]]--;
if (mp[v[next][i]] == 0) {
q.push(v[next][i]);
ans.push_back(v[next][i]);
}
}
}
for (int i = 0; i < ans.size(); i++) {
cout << ans[i] << " ";
}
cout<<endl;
}
return 0;
}
二、 dfs排序(栈+dfs)
思维:在拓扑排序中,部分点是没有关系的,所以可以任意决定它们的位置,
只需要判断某一条链上的顺序就行其他的链并没有特定的关系。故而可以一条链一条链的判断,遍历到最后一个元素之后递归并将元素放入栈中,并记录该元素已经访问过,不需要再放入栈中,再将栈中的元素输出,即可得到结果。(判断环,则是找某一条链有无某个元素的下一个元素指向前方的元素,若指向则是环,不能拓扑排序。)(但是该题没有必要,所以我就没写了😁(关键是懒~))
//
// Created by fallrain on 2020/8/24.
//
#include <bits/stdc++.h>
using namespace std;
int n,m;
stack<int>s;
vector<int>v[105];
map<int,int>mp;
set<int>ss;
void dfs(int num)
{
for(int i=0;i<v[num].size();i++)
{
dfs(v[num][i]);
}
if(!ss.count(num))
{
s.push(num);
ss.insert(num);
}
return ;
}
int main()
{
while (cin >> n >> m)
{
while(!s.empty())
{
s.pop();
}
ss.clear();
mp.clear();
for(int i=1;i<=n;i++)
v[i].clear();
if(n==0&&m==0)
break;
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
mp[b]++;
v[a].push_back(b);
}
for(int i=1;i<=n;i++)
{
if(mp[i]==0)
{
dfs(i);
}
}
while(!s.empty())
{
cout<<s.top()<<" ";
s.pop();
}
cout<<endl;
}
return 0;
}