这个主要是受一个博主的启发,才想明白的。附上链接——
链接传送门——
拓扑排序其实就是不断的将入度为零的点,和这个点指出的边删掉维护新的图,不断重复的操作;同时也可以用来判环;
#include<cstdio>
#include<queue>
#define pointnumber 100005
using namespace std;
queue<int>edg[pointnumber];//保存每个点的的出边指向点的编号
int getin[pointnumber];//保存每个点入边的数量,也就是入度
queue<int>q;//用来保存每次更新完后入边为零的点的编号(可以改为优先队列保证字典序)
queue<int>ans;//保存拓扑序列
int n,m;
void init()//初始化
{
while(!ans.empty()) ans.pop();//先将ans遍历出队,变为空队列
q=ans; //用空队列ans对q初始化
for(int i=1;i<=n;i++)
{
edg[i]=q;//用空队列ans对edg初始化
getin[i]=0;
}
return ;
}
int main()
{
int i,j,T,a,b;
scanf("%d",&T);
for(;T>=1;T--)//T组数据
{
scanf("%d%d",&n,&m);//n保存点的数量m保存有向边的数量
init();//初始化
for(i=1;i<=m;i++)//读入m条边
{
scanf("%d%d",&a,&b);//a指向b
getin[b]++;
edg[a].push(b);//保存入edg
}
for(i=1;i<=n;i++)
{
if(0==getin[i])
{
q.push(i);//遍历每个点,将入度为零的点入队
}
}
while(!q.empty())//只要还有入度为零的点就继续;
{
i=q.front();q.pop();//取出入度为零的点;
ans.push(i);//计入拓扑序列
while(!edg[i].empty())//将入度为零的点指向的点更新一遍
{
j=edg[i].front();edg[i].pop();//取出i点指向的点
getin[j]--;//j点入度减一
if(getin[j]==0)
{
q.push(j);//更新后如果入度为零,加入队列
}
}
}
if(n==ans.size())//如果所有点都能加入拓扑序列,说明无环;
{
printf("Correct\n");
}
else//反之,有环;
{
printf("Wrong\n");
}
}
return 0;
}