1. 题面梗概
中译中: 一条铁路线上,有 1,…,n 的 n 个火车站。每个火车站都有一个级别,最低为 1 级。
限制条件:如果这趟车停靠了 x 站点,则所有从它起点到终点间级别大于等于 x 的都必须停靠。
现给出多趟列车的信息,求全图最少需要划分为多少个级别。
2. 逻辑推导
这看起来是一个分层图,或者说是按层遍历,直觉上就会想到用拓扑排序找出这个级别划分。
2.1 偏序
其实每一趟车都产生了一组偏序关系。假设 [L,R] 区间中,停靠集合为 S,未停靠集合为 U,则对于 ∀u∈U,∀s∈S,存在约束条件 level(u)<level(s)。
而题目要求的 最少级别数,在图论中就等价于求 DAG 上的最长路径长度。
2.2 建图
那么问题就转化为了拓扑排序,下一个问题是怎么建图呢?暴力建图复杂度应该没关系,但是重边会导致入度膨胀,从而导致拓扑错误。
正好 N≤1000,我们可以考虑用邻接矩阵来存图,自动去重边。
2.3 结论
哎,拓扑排序不难,但是建模真的很麻烦。
3. 代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| #include <bits/stdc++.h> using namespace std; using ll = long long;
const int maxn = 1000 + 5; const int maxm = 1000 + 5;
bool edge[maxn][maxn]; int stop[maxn]; bool is_stop[maxn]; int indeg[maxn]; int dep[maxn]; int n, m, s;
void solve( ) { cin >> n >> m; for( int i = 1; i <= m; ++ i ) { cin >> s; for( int j = 1; j <= n; ++ j ) is_stop[j] = 0; for( int j = 1; j <= s; ++ j ) { cin >> stop[j]; is_stop[stop[j]] = 1; }
for( int j = stop[1]; j <= stop[s]; ++ j ) { if( is_stop[j] ) continue;
for( int k = 1; k <= s; ++ k ) { if( !edge[j][stop[k]] ) { edge[j][stop[k]] = 1; indeg[stop[k]] ++; } } } }
queue< int > q; for( int i = 1; i <= n; ++ i ) { if( indeg[i] == 0 ) { q.push( i ); dep[i] = 1; } }
while( !q.empty( ) ) { int u = q.front( ); q.pop( );
for( int v = 1; v <= n; ++ v ) { if( edge[u][v] ) { dep[v] = dep[u] + 1; indeg[v] --; if( indeg[v] == 0 ) q.push( v ); } } }
int ans = 0; for( int i = 1; i <= n; ++ i ) { ans = max( ans, dep[i] ); } cout << ans << '\n'; }
int main( ) { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); solve( ); return 0; }
|
4. 复盘