【luogu1137】【图论】旅行计划

传送门

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 21,两点可随意选一点。所以一个有向图的拓扑排序不唯一。这里暂且按字典顺序求。
记录起点 k = k= k= { 0 , 1 , 2 0,1,2 0,1,2 }
1 1 1为起点,删掉两条边, 4 、 3 4、3 43的入度减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]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值