NC16541 [NOIP2013]车站分级

题目链接

题目

题目描述

一条单向的铁路线上,依次有编号为1, 2, …, n 的n 个火车站。每个火车站都有一个级别,最低为1 级。现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站x,则始发站、终点站之间所有级别大于等于火车站x 的都必须停靠。(注意:起始站和终点站自然也算作事先已知需要停靠的站点)

例如,下表是5 趟车次的运行情况。其中,前4 趟车次均满足要求,而第5 趟车次由于停靠了3 号火车站(2 级)却未停靠途经的6 号火车站(亦为2 级)而不满足要求。

车站编号 1 2 3 4 5 6 7 8 9
车次/车站级别 3 1 2 1 3 2 1 1 3
1
2
3
4
5

输入描述

第一行包含2个正整数n,m,用一个空格隔开。
第 i + 1 行(1 ≤ i ≤ m)中,首先是一个正整数 si(2 ≤ si ≤ n),表示第 i 趟车次有 si 个停靠站;接下来有si 个正整数,表示所有停靠站的编号,从小到大排列。
每两个数之间用一个空格隔开。输入保证所有的车次都满足要求。

输出描述

输出只有一行,包含一个正整数,即n个火车站最少划分的级别数。

示例1

输入

9 2
4 1 3 5 6
3 3 5 6

输出

2

示例2

输入

9 3
4 1 3 5 6
3 3 5 6
3 1 5 9

输出

3

备注

对于20%的数据,1 ≤n,m ≤10;
对于50%的数据,1 ≤n,m≤100;
对于100%的数据,1 ≤n,m ≤ 1000。

题解

知识点:图论建模,拓扑排序。

容易知道一条线路范围内的所有车站的级别关系,停靠站级别一定大于不停靠站。因此可以用一个虚拟点来模拟每条线路得到站点的大小关系,级别大的建一条边指向这个点,级别小的从这个点出发建一条边指向自己。用这个图拓扑排序,求排序的最大深度,即站点需要分为几个级别。需要注意的是,每层中间夹着虚拟点,如果深度从 \(0\) 开始计算,那么最后实际深度应该是 \(\lfloor \frac{dep}{2} \rfloor + 1\)

时间复杂度 \(O(n+m+\sum s_i)\)

空间复杂度 \(O(n+m+\sum s_i)\)

代码

#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int N = 1007 << 1, M = 1007 * 1007;

int n, m;

struct edge {
    int v, nxt;
}e[M];
int h[N], idx;
void add(int u, int v) {
    e[++idx] = { v,h[u] };
    h[u] = idx;
}

int deg[N], dep[N];
queue<int> q;
void toposort() {
    for (int i = 1;i <= n + m;i++) if (!deg[i]) q.push(i), dep[i] = 0;
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int i = h[u];i;i = e[i].nxt) {
            int v = e[i].v;
            dep[v] = dep[u] + 1;
            deg[v]--;
            if (!deg[v]) q.push(v);
        }
    }
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n >> m;
    for (int i = 1;i <= m;i++) {
        int s;
        cin >> s;
        vector<int> vis;
        for (int j = 1;j <= s;j++) {
            int u;
            cin >> u;
            vis.push_back(u);
        }
        for (int j = vis.front(), k = 0;j <= vis.back();j++) {
            if (j == vis[k]) {
                add(n + i, j);
                deg[j]++;
                k++;
            }
            else {
                add(j, n + i);
                deg[n + i]++;
            }
        }
    }
    toposort();
    cout << *max_element(dep + 1, dep + n + m + 1) / 2 + 1 << '\n';///每个级别夹着一个站点,且深度从0计算
    return 0;
}
posted @ 2023-01-02 19:25  空白菌  阅读(20)  评论(0编辑  收藏  举报