【SSL】2264 &【洛谷】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)中,首先是一个正整数 (2≤si ≤n),表示第i 趟车次有 si个停靠站;接下来有si个正整数,表示所有停靠站的编号,从小到大排列。每两个数之间用一个空格隔开。输入保证所有的车次都满足要求。
输出格式
一个正整数,即 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。
思路
在路径上的点级别大于不在路径上的点级别。
建边。
判重边。
减小重边占用的空间。
代码
slow
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
int ans[1010],tot=0,n,m,head[1010],ins[1010],a[1010];
bool b[1010][1010];
struct jgt
{
int x,y,nxt;
}f[1000010];
queue<int> q;
void input()
{
int i,j,k,l,t;
memset(head,0,sizeof(head));
memset(ins,0,sizeof(ins));
memset(ans,0,sizeof(ans));
memset(b,0,sizeof(b));
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
memset(a,0,sizeof(a));
scanf("%d",&t);
for(j=1;j<=t;j++)
scanf("%d",&a[j]);
for(j=1;j<=t;j++)
{
for(k=a[1]+1,l=2;k<a[t];k++)
{
if(k==a[l])
l++;
else
{
if(!b[k][a[j]])//判重边
{
tot++;
f[tot].x=k;
f[tot].y=a[j];
f[tot].nxt=head[k];
head[k]=tot;
ins[a[j]]++;
b[k][a[j]]=1;
}
}
}
}
}
return;
}
void topsort()
{
int i,answer=0;
for(i=1;i<=n;i++)
if(!ins[i])
{
q.push(i);
ans[i]=1;
}
for(;!q.empty();q.pop())
{
for(i=head[q.front()];i;i=f[i].nxt)//更新入度
{
ins[f[i].y]--;
ans[f[i].y]=max(ans[f[i].y],ans[q.front()]+1);
if(!ins[f[i].y])//当能够到达这个点的所有点都遍历过后将这个点加入队列
q.push(f[i].y);
}
}
for(i=1;i<=n;i++)
answer=max(answer,ans[i]);
printf("%d",answer);
return;
}
int main()
{
input();
topsort();
return 0;
}
fast
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
int ans[1010],tot=0,n,m,head[1010],ins[1010],a[1010];
int i,j,k,l,t,answer,tem;
bool b[1010][1010];
int x[1000010],y[1000010],nxt[1000010];
queue<int> q;
int read()//快读
{
int ans=0;
char c;
for(c=getchar();c<'0'||c>'9';c=getchar());
for(ans=c-48,c=getchar();'0'<=c&&c<='9';c=getchar())ans=(ans<<3)+(ans<<1)+c-48;
return ans;
}
int main()
{
n=read(),m=read();
for(i=1;i<=m;i++)
{
t=read();
for(j=1;j<=t;j++)
a[j]=read();
k=a[1]+1;
for(j=2;j<=t;j++,k++)
for(;k<a[j];k++)
for(l=1;l<=t;l++)
if(!b[k][a[l]])//判重边
{
tot++;
x[tot]=k;
y[tot]=a[l];
nxt[tot]=head[k];
head[k]=tot;
ins[a[l]]++;
b[k][a[l]]=1;
}
}
for(i=1;i<=n;i++)
if(!ins[i])
{
q.push(i);
ans[i]=1;
}
for(;!q.empty();q.pop())
for(tem=q.front(),i=head[tem];i;i=nxt[i])//更新入度
{
ins[y[i]]--;
ans[y[i]]=max(ans[y[i]],ans[tem]+1);
if(!ins[y[i]])//当能够到达这个点的所有点都遍历过后将这个点加入队列
q.push(y[i]);
}
for(i=1;i<=n;i++)
answer=max(answer,ans[i]);
printf("%d",answer);
return 0;
}