【题目描述】
一条单向的铁路线上,依次有编号为
1
,
2
,
…
,
n
1,2,\dots ,n
1,2,…,n的
n
n
n个火车站。每个火车站都有一个级别,最低为
1
1
1级。现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站
x
x
x,则始发站、终点站之间所有级别大于等于火车站
x
x
x的都必须停靠。(注意:起始站和终点站自然也算作事先已知需要停靠的站点)
例如,下表是
5
5
5趟车次的运行情况。其中,前
4
4
4趟车次均满足要求,而第
5
5
5趟车次由于停靠了
3
3
3号火车站(
2
2
2级)却未停靠途经的
6
6
6号火车站(亦为
2
2
2级)而不满足要求。
现有 m m m趟车次的运行情况(全部满足要求),试推算这 n n n个火车站至少分为几个不同的级别。
【输入格式】
第一行包含
2
2
2个正整数
n
,
m
n,m
n,m,用一个空格隔开。
第
i
+
1
i+1
i+1行
(
1
≤
i
≤
m
)
(1\le i\le m)
(1≤i≤m)中,首先是一个正整数
s
i
(
2
≤
s
i
≤
n
)
s_i(2\le s_i\le n)
si(2≤si≤n),表示第
i
i
i趟车次有
s
i
s_i
si个停靠站;接下来有
s
i
s_i
si个正整数,表示所有停靠站的编号,从小到大排列。每两个数之间用一个空格隔开。输入保证所有的车次都满足要求。
【输出格式】
一个正整数,即
n
n
n个火车站最少划分的级别数。
【数据范围】
1
≤
n
,
m
≤
1000
1\le n,m\le 1000
1≤n,m≤1000
【输入样例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
【分析】
根据题目的意思,如果你停靠了一个站点,所有等级大于等于这个站点的站点都要停靠,反过来也就是所有起始站和终点站中间没有停靠的站点的等级一定小于停靠的站点。所以我们将起点到终点所有没停靠的站点向停靠的站点连边,然后进行一次拓扑排序求出这个图的层数就可以了。注意连边的时候需要标记一下防止重复连边。
【代码】
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1010, M = 1000010;
int e[M], ne[M], h[N], idx;
int in[N], lv[N], stop[N];//in表示每个点的入度,lv表示每个点的层数,stop表示车站的位置
bool st[N], has_edge[N][N];//st表示是否为停靠站,has_edge表示两点之间是否已有边
int n, m, res;
void add(int u, int v)
{
e[idx] = v, ne[idx] = h[u], h[u] = idx++;
}
void topSort()
{
queue<int> Q;
for (int i = 1; i <= n; i++)
if (!in[i]) Q.push(i), lv[i] = 1;
while (Q.size())
{
int t = Q.front();
Q.pop();
for (int i = h[t]; ~i; i = ne[i])
if (!--in[e[i]]) Q.push(e[i]), lv[e[i]] = lv[t] + 1, res = max(res, lv[e[i]]);
}
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof h);
while (m--)
{
memset(st, false, sizeof st);
int s;
cin >> s;
for (int i = 1; i <= s; i++) { cin >> stop[i]; st[stop[i]] = true; }
for (int i = stop[1]; i <= stop[s]; i++)//枚举起点站和终点站间的所有站
if (!st[i])//如果这个点不是停靠站
for (int j = 1; j <= s; j++)//从这个点向所有停靠站连边
if (!has_edge[i][stop[j]])//注意判断防止重复连接
add(i, stop[j]), in[stop[j]]++, has_edge[i][stop[j]] = true;
}
topSort();
cout << res << endl;
return 0;
}