CSP历年复赛题-P1983 [NOIP2013 普及组] 车站分级
原题链接:https://www.luogu.com.cn/problem/P1983
题意解读:由于“如果这趟车次停靠了火车站,则始发站、终点站之间所有级别大于等于火车站的都必须停靠”。因此,在始发站和终点站之间,能停靠的车站都是级别较高的,没有停靠的车站都是级别较低的,计算最少有多少个不同级别。
解题思路:
有若干车站可以是同一个级别,如未停靠的车站都可以设置同样的低级别,停靠的车站根据相关关系也可以划分不同的级别,可以通过建图形成层级关系。
由于停靠的车站都是级别较高的,未停靠的车站都是级别较低的,所以对于起点、终点之间每一个未停靠的车站,可以建立一条指向停靠车站的边
对样例进行模拟
9 2
4 1 3 5 6
3 3 5 6
图中2、4是未停靠站,可以设定同样的级别,1、3、5、6是停靠站,也可以设定同样的级别,因此一共只需要2个级别。
在图形结构中,2、4是拓扑排序的第一层,1、3、5、6是拓扑排序的第二层。
有了这个设想,在用另外一个样例进行模拟,验证是否正确
9 3
4 1 3 5 6
3 3 5 6
3 1 5 9
上图中,2、4、7、8是拓扑排序的第一层、3、6是拓扑排序的第二层,1、5、9是拓扑排序的第三层,因此一共只需要3个级别。
此方法验证成立。
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int g[N][N]; //邻接矩阵,便于处理重边的情况
int n, m, s, a[N], b[N]; //a[i]存储所有停靠点 b[i]=1表示在第i站停靠
int in[N];
int depth[N], ans = 1;
//通过拓扑排序,计算每个节点所在的深度,最大深度即不同的级别数
void bfs()
{
queue<int> q;
for(int i = 1; i <= n; i++)
{
if(in[i] == 0)
{
q.push(i);
depth[i] = 1; //初始节点的深度
}
}
while (q.size())
{
int u = q.front(); q.pop();
for(int v = 1; v <= n; v++)
{
if(g[u][v] == 1)
{
if(--in[v] == 0)
{
q.push(v);
depth[v] = depth[u] + 1;
ans = max(ans, depth[v]);
}
}
}
}
}
int main()
{
cin >> n >> m;
while(m--)
{
cin >> s;
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
for(int i = 1; i <= s; i++)
{
cin >> a[i]; //所有停靠站
b[a[i]] = 1; //停靠站和非停靠站
}
for(int i = a[1]; i <= a[s]; i++) //遍历起点到终点之间的站
{
if(b[i] == 0)//取未停靠站
{
for(int j = 1; j <= s; j++) //遍历每一个停靠站a[j]
{
if(g[i][a[j]] == 0) in[a[j]]++; //记录入度,去重边
g[i][a[j]] = 1; //所有未停靠站和所有停靠站之间建立边
}
}
}
}
bfs();
cout << ans;
return 0;
}