【洛谷P1983】车站分级【拓扑排序】

题目描述

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

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

在这里插入图片描述

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

输入格式

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

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

输出格式

一个正整数,即 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%的数据,1 ≤ n, m ≤ 10;

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

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

分析

题目中说,如果这趟车次停靠了火车站 x,则始发站、终点站之间所有级别大于等于火车站 x 的都必须停靠。也就是说,这趟车次经过且不停靠的所有车站的级别都必须小于这趟车次停靠的所有车站的级别。
可以确定他们之间的大小关系,停靠点站与不停靠的站连一条单向边,然后加入拓扑排序得出合法的他们之间的关系。

上代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

int n,m,x,ans,a[1001][1001],v[1001],in[1001],h,t,q[1001],f[1001],b[1001];

void topsort()
{
	memset(v,0,sizeof(v));
	for(int i=1;i<=n;i++)
	{
		if(in[i]==0)//找到一个入度为0的边 
		{
			t++;
			q[t]=i;
			f[i]=1;
			v[i]=1;
		}
	}
	while(h<t)
	{
		h++;
		for(int i=1;i<=n;i++)
	    {
	    	if(a[q[h]][i]==1&&v[i]==0)
	    	{
	    		in[i]--;
	    		if(in[i]==0)
	    		{
	    			f[i]=f[q[h]]+1;
	    			ans=max(ans,f[i]);
	    			v[i]=1;
	    			t++;
	    			q[t]=i;
	    		}
	    	}
	    }
	}
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
    	cin>>x;
    	memset(v,0,sizeof(v));
    	for(int j=1;j<=x;j++)
    	{
    		cin>>b[j];
    		v[b[j]]=1;
    	}
    	for(int j=b[1];j<=b[x];j++)
    	{
    		if(v[j]==0)
    		{
    			for(int k=1;k<=x;k++)
    			{
    				if(a[j][b[k]]==0)
    				{
    					in[b[k]]++;//入度++
						a[j][b[k]]=1;//建边 
    				}
    			}
    		}
    	}
    }
    topsort();
	cout<<ans; 
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值