题目描述 Description
一条单向的铁路线上,依次有编号为1, 2, …, n的n个火车站。每个火车站都有一个级别,最低为1级。现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站x,则始发站、终点站之间所有级别大于等于火车站x的都必须停靠。(注意:起始站和终点站自然也算作事先已知需要停靠的站点)
例如,下表是5趟车次的运行情况。其中,前4趟车次均满足要求,而第5趟车次由于停靠了3号火车站(2级)却未停靠途经的6号火车站(亦为2级)而不满足要求。
现有m趟车次的运行情况(全部满足要求),试推算这n个火车站至少分为几个不同的级别。
思路: 本来是想通过普及组的水题找自信的,但是浪费了我两个小时。。。真是醉了。。。看完题后,想到了拓扑排序,将这一趟火车始发站和终点站中没有出现的站点向出现的站点连一条有向边,拓扑排序查出有几层就可以了。但是,这里有一个问题,就是o(mn^2)的读入,和较大的计算量,于是就将读入稍稍减小了一些循环范围,达到最差o(mn^2/4)的读入复杂度。在拓扑排序中,也有一个小小的优化,每一层的入度为0的点都是又上一层删边时产生的,所以在删边的时候就可以将点加入到下一层中去,减少时间复杂度。
code:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct use{
int num[1001],l;
}uc,ucc;
bool map[1001][1001]={false};
int r[1001]={0},bian[1001][1001]={0};
void work()
{
int tot=0,n,m,i,j,k,q,x,ans=0;
scanf("%d%d",&n,&m);
for (i=1;i<=m;++i)
{
scanf("%d",&q);
uc.l=q;ucc.l=0;
scanf("%d",&uc.num[1]);
for (j=2;j<=q;++j)
{
scanf("%d",&uc.num[j]);
for (k=uc.num[j-1]+1;k<uc.num[j];++k)
{
++ucc.l;ucc.num[ucc.l]=k;
}
}
for (j=1;j<=uc.l;++j)
for (k=1;k<=ucc.l;++k)
{
if (!map[ucc.num[k]][uc.num[j]])
{
map[ucc.num[k]][uc.num[j]]=true;
++bian[ucc.num[k]][0];
bian[ucc.num[k]][bian[ucc.num[k]][0]]=uc.num[j];
++r[uc.num[j]];
}
}
}
uc.l=0;
for (i=1;i<=n;++i)
if (r[i]==0)
{
++uc.l;
uc.num[uc.l]=i;
}
tot=uc.l;
ans=1;
while (tot<n)
{
ucc.l=0;
for (i=1;i<=uc.l;++i)
for (j=1;j<=bian[uc.num[i]][0];++j)
{
--r[bian[uc.num[i]][j]];
if (r[bian[uc.num[i]][j]]==0)
{
++ucc.l;
ucc.num[ucc.l]=bian[uc.num[i]][j];
}
}
uc=ucc;
tot=tot+uc.l;
++ans;
}
cout<<ans<<endl;
}
int main()
{
work();
}