You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

91 lines
3.1 KiB

2 years ago
#include <bits/stdc++.h>
using namespace std;
const int N = 2010, M = 1000010;
const int INF = 0x3f3f3f3f;
int n, m;
int in[N];
int d[N];
int st[N];
// 邻接表
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
vector<int> path; // 拓扑路径
void topsort() {
queue<int> q;
/*
0,
*/
for (int i = 1; i <= n + m; i++)
if (!in[i]) q.push(i);
while (q.size()) {
int u = q.front();
q.pop();
path.push_back(u);
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
in[j]--;
if (in[j] == 0) q.push(j);
}
}
}
int main() {
// 加快读入
ios::sync_with_stdio(false), cin.tie(0);
// 建图
memset(h, -1, sizeof h);
cin >> n >> m; // n个火车站,m趟车次
for (int i = 1; i <= m; i++) {
memset(st, 0, sizeof st); // 记录哪些是停靠点
int k;
cin >> k; // 有多少个依靠站
int S = n, T = 1;
for (int j = 1; j <= k; j++) {
int x; // 停靠站编号
cin >> x;
S = min(S, x); // 第一个停靠点
T = max(T, x); // 最后一个停靠点
st[x] = 1; // 记录哪些是停靠点,哪些不是停靠点
}
// 笛卡尔积式建图优化技巧
int u = n + i; // 分配超级源点虚拟点点号。多条线路每次一个超级源点共多建超级源点m个
for (int j = S; j <= T; j++)
if (st[j]) // 如果j不是停靠点
add(u, j, 1), in[j]++; // 虚拟点向右侧集合中每个点连一条长度为1的边
else
add(j, u, 0), in[u]++; // 左侧集合向 虚拟点u 连一条长度为0的边
}
// 求拓扑序
topsort();
/*
Q:for (int i = 1; i <= n; i) d[i] = 1;
y for (int i = 1; i <= n + m; i) d[i] = 1;
A:,0d0
1,12
*/
// 递推距离初始化
for (int i = 1; i <= n; i++) d[i] = 1; // n个站点的等级最少是1而虚拟节点的等级最少是0
// 拓扑路径+递推计算最长路
for (auto u : path) // 枚举拓扑路径的每一个点
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
d[j] = max(d[j], d[u] + w[i]); // u要求j必须距离自己>=w[i]
}
int res = 0;
for (int i = 1; i <= n; i++) res = max(res, d[i]); // 找出最大值,就是最小等级
printf("%d\n", res);
return 0;
}