P1983 [NOIP 2013 普及组] 车站分级 题解
前言
你知道你入度为 \(0\) 吗?
因为你要入队了。
思路
这道题要求至少分为几个不同的级别,那么首先想到的就是拓扑排序。
如何建图呢?
我们知道,每趟列车运行情况中,所有没有停靠的站点级别必定比已经停靠的站点级别小。是不是有思路了?我们只需要让级别小的站点指向级别大的站点,然后跑拓扑排序即可。
具体的,让每次没有停靠的站点指向停靠的站点。下图为样例 \(1\) 的图(没有 \(7,8,9\) 三个点)
.png)
最后只需要看级别最高的是多少即可。
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define int long long
#define ___ __int128
#define INF 0x3f3f3f3f3f3f3f3f
inline int Read(){
int x=0,f=1;
char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-48;c=getchar();}
return x*f;
}
inline void Write(int x){
if(x<0) {putchar('-');x=-x;}
if(x>9) Write(x/10);
putchar(x%10+'0');
}
const int N=1e3+10,M=5e5+10;
int n,m,a[N],d[N],rk[N],ans;
//d[i]:i 结点入度
//rk[i]:i 车站级别
bool g[N][N],vis[N];
//g[i][j]:i 和 j 之间有没有连边,去重用的
struct node{
int nxt,to;
}e[M];//边的数组一定不要开小
int head[N],num_Edge=0;
void add_Edge(int from,int to){
e[++num_Edge].nxt=head[from];
e[num_Edge].to=to;
head[from]=num_Edge;
}
queue<int> q;
signed main(){
n=Read();m=Read();
while(m--){
for(int i=1;i<=n;i++) vis[i]=0;//vis[i]:本次是否停靠
int k=Read();
for(int i=1;i<=k;i++){
int x=Read();
vis[x]=1;
a[i]=x;
}
for(int i=a[1];i<=a[k];i++){
if(!vis[i]){
for(int j=1;j<=k;j++){
if(g[i][a[j]]) continue;
add_Edge(i,a[j]);
d[a[j]]++;
g[i][a[j]]=1;
}
}
}
}
//拓扑排序板子
for(int i=1;i<=n;i++){
if(!d[i]) {
q.push(i);
rk[i]=1;
}
}
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
rk[v]=max(rk[v],rk[u]+1);
d[v]--;
if(!d[v]) q.push(v);
}
}
for(int i=1;i<=n;i++){
ans=max(ans,rk[i]);
}
printf("%lld\n",ans);
return 0;
}
浙公网安备 33010602011771号