解析
什么是拓扑序?
拓扑序是指每一个起点一定在终点前,列如下面这种图:
如果是这样的话就不是拓扑图了:
这样的话3就在1前面了
因此不难发现,拓扑图都是一个有向无环图。
证明
反证法,我们去证明一个有环图一定不是拓扑序列。
对于拓扑图的每一个点都一定有一个点有0个入度。
如果是一个有环图,那么该图一定不是拓扑图(因为有环图中每个节点都一定至少有1个进度)。
证毕
拓扑图的特点
对于一个有向无环图一定有一个入度为0的点,像下面这个拓扑图中1这个节点就没有入度:
因此所有入度为0的点,我们都可以将其视为一个起点。
1.我们可以用一个队列,我们先将所有入度为0的点入队,
2.然后枚举所有的出边t~x
3.运用bfs从所有入度为0的点开始突破队列,并且将该点指向的所有节点的入边+1,若减完之后d==0,就将该点入队列。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int h[N]; //头节点
int e[N]; //边值
int ne[N]; //指向下一个节点的指针
int idx; //地址
bool st[N]; //标记,防止一个点被走多次
int q[N];
int d[N]; //入度
bool topsort()
{
int hh = 0, tt = -1; //因为队列为空,所以从-1开始,要往队列中加入元素的时候先++,这样就会到0了,表示队头
for (int i = 1; i <= n; i++)
{
if (!d[i]) //如果没有入度
{
q[++tt] = i; //加入队列
}
}
while (hh <= tt)
{
int t = q[hh++];
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
d[j]--;
if (d[j] == 0) q[++tt] = j;
}
}
return tt == n - 1;
}
void add(int a, int b)
{
e[idx] = b; //把b赋值给边值
ne[idx] = h[a]; //头结点指向下一个节点
h[a] = idx++; //头节点跳到下一个节点
}
int main()
{
cin >> n >> m;
memset(h,-1,sizeof h);
for (int i = 0; i < m; i++)
{
int a, b; cin >> a >> b;
add(a, b);
d[b]++; //一条a指向b的边,b的入度++
}
//判断一下是否是拓扑序
if (topsort())
{
for (int i = 0; i < n; i++)
{
cout << q[i] << " ";
}cout << endl;
}
else
{
cout << -1 << endl;
}
return 0;
}