【luogu1983】【拓扑排序】车站分级

传送门

题目描述

一条单向的铁路线上,依次有编号为 1 , 2 , … , n 1, 2, …, n 1,2,,n n n n个火车站。每个火车站都有一个级别,最低为 1 1 1 级。现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站 x x x,则始发站、终点站之间所有级别大于等于火车站 x x x的都必须停靠。(注意:起始站和终点站自然也算作事先已知需要停靠的站点)

例如,下表是 5 5 5趟车次的运行情况。其中,前 4 4 4趟车次均满足要求,而第 5 5 5趟车次由于停靠了 3 3 3号火车站( 2 2 2级)却未停靠途经的 6 6 6号火车站(亦为 2 2 2级)而不满足要求。

现有 m m m趟车次的运行情况(全部满足要求),试推算这 n n n个火车站至少分为几个不同的级别。

输入格式

第一行包含 2 2 2个正整数 n , m n, m n,m,用一个空格隔开。

i + 1 i + 1 i+1 ( 1 ≤ i ≤ m ) (1 ≤ i ≤ m) (1im)中,首先是一个正整数 s i ( 2 ≤ s i ≤ n ) s_i(2 ≤ s_i ≤ n) si(2sin),表示第 i i i 趟车次有 s i s_i si 个停靠站;接下来有 s i s_i si​个正整数,表示所有停靠站的编号,从小到大排列。每两个数之间用一个空格隔开。输入保证所有的车次都满足要求。

输出格式

一个正整数,即 n n n 个火车站最少划分的级别数。

输入输出样例
输入 #1
9 2 
4 1 3 5 6 
3 3 5 6 
输出 #1
2
输入 #2
9 3 
4 1 3 5 6 
3 3 5 6 
3 1 5 9 
输出 #2
3
说明/提示

对于 20 % 20\% 20%的数据, 1 ≤ n , m ≤ 10 1 ≤ n, m ≤ 10 1n,m10

对于 50 % 50\% 50%的数据, 1 ≤ n , m ≤ 100 1 ≤ n, m ≤ 100 1n,m100

对于 100 % 100\% 100%的数据, 1 ≤ n , m ≤ 1000 1 ≤ n, m ≤ 1000 1n,m1000


解题思路

拓扑排序+记录一下深度


Code
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct DT{
	int to,next;
}a[500010];
int n,m,si,h,t,ans,num,f[10010],s[10010],ru[10010],q[100100],v[10010],sa[1100][1100],head[10010];
void add(int x,int y){
	a[++num]=(DT){y,head[x]};
	head[x]=num;
}
void tuop(){//拓扑
	for(int i=1;i<=n;i++)
	    if(!ru[i])
	    	q[++t]=i,f[i]=1;
	while(h++<t)
		for(int i=head[q[h]];i;i=a[i].next){
		    ru[a[i].to]--;
		    if(ru[a[i].to]<=0){
		    	q[++t]=a[i].to;
		        f[a[i].to]=max(f[a[i].to],f[q[h]]+1);//下传深度
		    }
		}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d",&si);
		memset(v,0,sizeof(v));
		for(int j=1;j<=si;j++){
		    scanf("%d",&s[j]);
		    v[s[j]]=1;
		} 
	    for(int j=s[1];j<=s[si];j++)
	        if(!v[j])
	            for(int k=1;k<=si;k++)
	                 sa[j][s[k]]=1;//没有停靠的向停靠的连边
	}
	for(int i=1;i<=n;i++)
	    for(int j=1;j<=n;j++)
	        if(sa[i][j]){
	        	add(i,j);
	        	ru[j]++;
	        }
	tuop();
	for(int i=1;i<=n;i++)
	    ans=max(ans,f[i]);
	printf("%d",ans);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值