传送门
Description
Input
Output
Sample Input
5 6
1 2
1 3
2 3
2 4
3 4
2 5
Sample Output
1
2
3
4
3
Hint
均选择从城市1出发可以得到以上答案。
对于20%的数据,N≤100;
对于60%的数据,N≤1000;
对于100%的数据,N≤100000,M≤200000。
解题思路
拓扑排序
拓扑排序:对于一个点p,只对排序位置在它之后的点有边。
用队列记录下每个点的入度
以入度为0的点为起点——
0
0
0,把起点记录
k
=
k=
k= {
0
0
0 }
把这个点的出度所连接的点的入度减1,等于删掉了这个点的出度
2
2
2和
1
1
1的入度被删为0
再次以入度为0的点为起点——
2
、
1
2、1
2、1,两点可随意选一点。所以一个有向图的拓扑排序不唯一。这里暂且按字典顺序求。
记录起点
k
=
k=
k= {
0
,
1
,
2
0,1,2
0,1,2 }
以
1
1
1为起点,删掉两条边,
4
、
3
4、3
4、3的入度减1
以
2
2
2为起点,删掉一条边,
4
4
4的入度被删为0
以此类推
。。。
。。。
。。。
k
=
k=
k= {
0
,
1
,
2
,
4
,
3
,
5
,
6
,
7
0,1,2,4,3,5,6,7
0,1,2,4,3,5,6,7 }
–因为只需要记录能经过多少点,那么就不需要记录下来图的拓扑序列。记录点数可以在拓扑排序过程中,设置一个数组 f a fa fa记录点数。
#include<iostream>
#include<cstdio>
using namespace std;
struct DT{
int to,next;
}a[4000400];
int n,m,s[2000000],fa[2000000],head[2000000],num;
int h,t,v[4004000],f[200000];
void demo(){
h=t=0;
for(int i=1;i<=n;i++)
if(!s[i])//以入度为0的点为起点
v[++t]=i,f[i]=1,fa[i]=1;
while(h++<t){
for(int i=head[v[h]];i;i=a[i].next){
if(!f[a[i].to]){
--s[a[i].to];//v[h]出度的点的入度减1
if(!s[a[i].to]){//以入度为0的点为起点
v[++t]=a[i].to;
f[a[i].to]=1;
}
fa[a[i].to]=max(fa[a[i].to],fa[v[h]]+1);//点数取max
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
a[++num].to=y,a[num].next=head[x],head[x]=num;
s[y]++;//记录入度
}
demo();
for(int i=1;i<=n;i++)
printf("%d\n",fa[i]);
}