【题目】
题目描述:
一条单向的铁路线上,依次有编号为 1,2,…, 的 个火车站。每个火车站都有一个级别,最低为 1 级。现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站 x,则始发站、终点站之间所有级别大于等于火车站 x 的都必须停靠。(注意:起始站和终点站自然也算作事先已知需要停靠的站点)
例如,下表是 5 趟车次的运行情况。其中,前 4 趟车次均满足要求,而第 5 趟车次由于停靠了 3 号火车站(2 级)却未停靠途经的 6 号火车站(亦为 2 级)而不满足要求。
现有 趟车次的运行情况(全部满足要求),试推算这 个火车站至少分为几个不同的级别。
输入格式:
第一行包含 2 个正整数 , ,用一个空格隔开。
第 行(1 ≤ ≤ )中,首先是一个正整数 (2 ≤ ≤ ),表示第 趟车次有 个停靠站;接下来有 个正整数,表示所有停靠站的编号,从小到大排列。每两个数之间用一个空格隔开。输入保证所有的车次都满足要求。
输出格式:
输出只有一行,包含一个正整数,即 个火车站最少划分的级别数。
样例数据:
【样例1】
输入
9 2 4 1 3 5 6 3 3 5 6
输出
2
【样例2】
输入
9 3 4 1 3 5 6 3 3 5 6 3 1 5 9
输出
3
备注:
【数据范围】
对于 20% 的数据,1 ≤ , ≤ 10;
对于 50% 的数据,1 ≤ , ≤ 100;
对于 100% 的数据,1 ≤ , ≤ 1000。
【分析】
一开始只是想写一个暴力骗骗分,结果改了一下就 A 了?
具体做法就是对于一个起点是 ,终点是 的车次,如果 到 中有车站没停,那么它们的级别肯定比停过的级别要低,那么就从没停的向停过的连一条边,表示它的级别相对比较低,最后拓扑排序,并且做一个简单递推即可
有一个地方要注意,就是要考虑重边,即如果当前已经有这条边,以后就不用加了(不然边数会很多,会炸掉)
emmm……好吧我还是没看懂这个O()的算法是怎么过的
【代码】
#include<stack>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1005
#define M 1000005
using namespace std;
int n,m,t,ans=1;
int a[N],f[N],du[N];
int v[M],next[M],first[N];
bool used[N],have[N][N];
stack<int>sta;
void add(int x,int y)
{
t++;
next[t]=first[x];
first[x]=t;
v[t]=y;
}
void link(int x,int s)
{
int i;
for(i=1;i<=s;++i)
{
if(!have[x][a[i]])
{
add(x,a[i]);
du[a[i]]++;
have[x][a[i]]=true;
}
}
}
void topology()
{
int x,i;
for(i=1;i<=n;++i)
if(!du[i])
f[i]=1,sta.push(i);
while(!sta.empty())
{
x=sta.top();
sta.pop();
for(i=first[x];i;i=next[i])
{
f[v[i]]=max(f[v[i]],f[x]+1);
ans=max(ans,f[v[i]]),--du[v[i]];
if(!du[v[i]]) sta.push(v[i]);
}
}
}
int main()
{
int s,i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=m;++i)
{
scanf("%d",&s);
memset(used,false,sizeof(used));
for(j=1;j<=s;++j)
{
scanf("%d",&a[j]);
used[a[j]]=true;
}
for(j=a[1];j<=a[s];++j)
if(!used[j])
link(j,s);
}
topology();
printf("%d",ans);
return 0;
}