[NOIP2013 普及组] 车站分级-题解
题目简述:一条单向的铁路线上,依次有编号为 $1, 2, …, n $的 $n $个火车站。每个火车站都有一个级别,最低为 \(1\) 级。现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站 \(x\),则始发站、终点站之间所有级别大于等于火车站$ x$ 的都必须停靠。(注意:起始站和终点站自然也算作事先已知需要停靠的站点)
现有 \(m\) 趟车次的运行情况(全部满足要求),试推算这 \(n\) 个火车站至少分为几个不同的级别。
若存在该车次 \(1,2\),
对于车次 \(1\):车站 \(2,4\) 的级别一定小于车站 \(1,3,5,6\) 的级别的最大值;
对于车次 \(2\):车站 \(4\) 的级别一定小于车站 \(3,5,6\) 的级别的最大值;否则车站的划分级别将不成立。
由此,我们可以将这 \(6\) 个车站进行划分
这样的话,令 \(2,4\) 的级别为最小的 \(1\),则 \(1,3,5,6\) 就为 \(2\)。
若增加车次 \(3\),
则有新的划分方式,其中 \(2,3,4,6,7,8\) 一定小于 \(1,5,9\) 的级别的最大值。
我们发现这已经很明显的分出来了级别,\(3\) 就是其答案。
建模:
对于每班车,也只是会影响在这班车的终点站和起点站之间(包含)的车站的级别。
我们将一定小于(到达的车站的级别)的车站[1]向到达的车站进行连边,然后得到其最深的节点的深度。
由于此图是一个 \(\text{DAG}\),所以利用 拓扑+DP 的方式解决。
(另外,你也可以使用一些高端的数据结构或其他,来优化这个 \(O(n^2m)\) 的建图。)
用 \(-1\) 代替了 \(3,6,7,8\) 四个点,否则这个图就太麻烦了。
其中 \(7\) 与 \(8\) 的位置不会对答案产生影响,因为题目对其的限制较小,但由于题目中并没有说到 \(7,8\) 小于 \(3,6\) 的情况,所以分级是上图 \(1\) 的情况。
#include <bits/stdc++.h>
using namespace std;
const int N = 1010, inf = 1e9 + 7;
int n, m, s, ans, d[N], in[N], f[N];
bool vis[N], g[N][N];
queue <int> q;
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; ++ i)
{
cin >> s;
for (int j = 1; j <= s; ++ j)
{
cin >> d[j];
vis[d[j]] = true;
}
for (int j = d[1]; j <= d[s]; ++ j)
{
if (! vis[j])
{
for (int k = 1; k <= s; ++ k)
{
if (!g[j][d[k]])
{
++ in[d[k]];
}
g[j][d[k]] = true;
}
}
}
for (int i = 1; i <= n; ++ i)
{
vis[i] = false;
}
}
for (int i = 1; i <= n; ++ i)
{
f[i] = -inf;
if (in[i] == 0)
{
q.push(i);
f[i] = 1;
}
}
while (!q.empty())
{
int u = q.front();
q.pop();
for (int v = 1; v <= n; ++ v)
{
if (g[u][v] && in[v])
{
f[v] = max(f[v], f[u]+1);
in[v] --;
if (in[v] == 0)
{
q.push(v);
}
}
}
}
for (int i = 1; i <= n; ++ i)
{
ans = max(ans, f[i]);
}
cout << ans << '\n';
return 0;
}
指的是这班车所跨域的车站中的。 ↩︎