[NOIP2013 普及组] 车站分级-题解

发布时间 2023-03-25 14:33:18作者: Ciaxin

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

现有 \(m\) 趟车次的运行情况(全部满足要求),试推算这 \(n\) 个火车站至少分为几个不同的级别。


若存在该车次 \(1,2\)

image

对于车次 \(1\):车站 \(2,4\) 的级别一定小于车站 \(1,3,5,6\) 的级别的最大值;

对于车次 \(2\):车站 \(4\) 的级别一定小于车站 \(3,5,6\) 的级别的最大值;否则车站的划分级别将不成立。

由此,我们可以将这 \(6\) 个车站进行划分

image

这样的话,令 \(2,4\) 的级别为最小的 \(1\),则 \(1,3,5,6\) 就为 \(2\)


若增加车次 \(3\)

image

则有新的划分方式,其中 \(2,3,4,6,7,8\) 一定小于 \(1,5,9\) 的级别的最大值。

image

我们发现这已经很明显的分出来了级别,\(3\) 就是其答案。


建模:我们将一定小于(到达的车站的级别)的车站[1]向到达的车站进行连边,然后得到其最深的节点的深度。

由于此图是一个 \(\text{DAG}\),所以利用 拓扑+DP 的方式解决。

(另外,你也可以使用一些高端的数据结构或其他,来优化这个 \(O(n^2m)\) 的建图。)

其中 \(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;
}

  1. 指的是这班车所跨域的车站中的。 ↩︎