题目描述
一条单向的铁路线上,依次有编号为 1, 2, …, n1,2,…,n的 nn个火车站。每个火车站都有一个级别,最低为 11 级。现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站 xx,则始发站、终点站之间所有级别大于等于火车站xx 的都必须停靠。(注意:起始站和终点站自然也算作事先已知需要停靠的站点)
例如,下表是55趟车次的运行情况。其中,前44 趟车次均满足要求,而第 55 趟车次由于停靠了 33 号火车站(22 级)却未停靠途经的 66 号火车站(亦为 22 级)而不满足要求。
现有 mm 趟车次的运行情况(全部满足要求),试推算这nn 个火车站至少分为几个不同的级别。
输入输出格式
输入格式:
第一行包含 22 个正整数 n, mn,m,用一个空格隔开。
第 i + 1i+1 行(1 ≤ i ≤ m)(1≤i≤m)中,首先是一个正整数 s_i(2 ≤ s_i ≤ n)si(2≤si≤n),表示第ii 趟车次有 s_isi 个停靠站;接下来有s_isi个正整数,表示所有停靠站的编号,从小到大排列。每两个数之间用一个空格隔开。输入保证所有的车次都满足要求。
输出格式:
一个正整数,即 nn 个火车站最少划分的级别数。
思路:拓扑排序,由于在火车从起点到终点所经过的所有站点一定比没有经过的站点级别高,并且多趟火车经过的次数越多的站点级别一定越高,联想到拓扑排序,建立一个DAG,在起始点内不能停靠的站向可以停靠的站连有向边,然后找到入度为0的点(没有边指向的点),删除这个点和这个点所连出去的所有路径,路径指向的点的入度-1,当所有入度为0的点(撤销原入度为0后入度变为0在第一轮不解决)都解决了之后,进行下一轮,进行一轮就累加一下计数器,最后输出结果即可。
代码:
#include <bits/stdc++.h>
#define INF 0x3fffffff
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define me(ar) memset(ar,0,sizeof(ar))
#define lowbit(x) (x&(-x))
#define IOS ios::sync_with_stdio(false)
#define DEBUG cout<<endl<<"DEBUG"<<endl;
using namespace std;
int n,m,t,b,w[1010][1010],cun[1010],da[1010],xiao[1010],to[1010],ans,fl[1010];
int main(){
cin>>n>>m;
for(int i=0;i<m;i++){//建图
cin>>t;int fi,gi,d=0,x=0;
for(int j=1;j<=t;j++){
cin>>b;
if(j==1)fi=b;
if(j==t)gi=b;
cun[b]=1;
}
for(int j=fi;j<=gi;j++){
if(cun[j]) da[d++]=j;
else xiao[x++]=j;
}
for(int j=0;j<d;j++){
for(int k=0;k<x;k++){
if(!w[da[j]][xiao[k]])to[da[j]]++;//统计
w[da[j]][xiao[k]]=1;//建立有向边
}
}
me(cun);
}
int tot=n;
while(tot){
ans++;
int ww[n],nu=0;
for(int i=1;i<=n;i++){
if(!to[i]&&!fl[i]){
tot--;//i拓扑完毕
fl[i]=1;
ww[nu++]=i;//统计被拓扑的点
}
}
for(int i=0;i<nu;i++){
for(int j=1;j<=n;j++){
if(w[j][ww[i]]||w[ww[i]][j])to[j]--;//删去被拓扑的点(拓扑后ww[i]链接的有向边就没用了)
}
}
}
cout<<ans;
return 0;
}