当前位置:首页 > 入门组 > 2013年NOIP普及组车站分级题解(洛谷P1983)— 图论与拓扑排序的实战应用

2013年NOIP普及组车站分级题解(洛谷P1983)— 图论与拓扑排序的实战应用

2个月前 (07-26)

2013年NOIP普及组车站分级题解(洛谷P1983)— 图论与拓扑排序的实战应用 NOIP普及组 拓扑排序 图论算法 第1张

一、题目解读

“车站分级”是2013年NOIP普及组的经典题目(洛谷P1983)。题目要求根据车次停靠信息,为每个车站分配级别:若某车站被所有车次停靠,则为最高级;若仅被部分车次停靠,则级别取决于其连接的非停靠站的级别。核心在于将实际问题转化为图论模型,通过拓扑排序求解。

二、解题思路

用户提供的代码采用论+拓扑排序策略。首先,用邻接表(graph)存储车站间的“非停靠站→停靠站”边关系,入度数组(in_degree)记录每个车站的入边数。通过遍历每趟车次的停靠站,将非停靠站指向所有停靠站,构建有向图。随后利用拓扑排序计算每个站的级别:入度为0的站(无依赖)初始化级别为1,逐级传递并更新相邻站的级别,最终得到最高级别。

三、解题步骤详解

1. 输入处理:读取车站数n和车次数m,循环处理每趟车。

2. 构建图:

    标记当前车次的停靠站(is_stop)。

    遍历区间内非停靠站,向所有停靠站连边(若边不存在则添加),并增加停靠站的入度。

3. 拓扑排序:

    初始化队列:入度为0的站加入队列,级别设为1。

    循环直至队列为空:

        取出队首站u,遍历其所有出边(v)。

        更新v的级别:level[v] = max(level[v], level[u] + 1),记录最高级别。

        若v的入度减至0,则加入队列。

4. 输出结果:最高级别即为答案。

四、代码与注释

#include <bits/stdC++.h>
using namespace std;

const int MAXN = 1005;
vector<int> graph[MAXN];  // 邻接表存储图
int in_degree[MAXN];      // 入度数组
int level[MAXN];          // 记录每个站点的级别
bool is_stop[MAXN];       // 标记是否为停靠站
vector<int> stops;        // 临时存储每趟车的停靠站

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n, m;
    cin >> n >> m;
    
    while (m--) {   // 处理每趟车
        int s;
        cin >> s;
        stops.clear();
        memset(is_stop, false, sizeof(is_stop));
        
        // 读取停靠站信息
        for (int i = 0; i < s; ++i) {
            int x;
            cin >> x;
            stops.push_back(x);
            is_stop[x] = true;  // 标记停靠站
        }
        
        // 构建边的关系:非停靠站级别 < 停靠站级别
        for (int i = stops[0]; i <= stops.back(); ++i) {  // 遍历区间内所有站
            if (!is_stop[i]) {  // 非停靠站
                for (int j : stops) {  // 所有停靠站
                    if (find(graph[i].begin(), graph[i].end(), j) == graph[i].end()) {
                        graph[i].push_back(j);  // 添加边
                        in_degree[j]++;        // 增加入度
                    }
                }
            }
        }
    }
    
    // 拓扑排序
    queue<int> q;
    for (int i = 1; i <= n; ++i) {
        if (in_degree[i] == 0) {
            q.push(i);
            level[i] = 1;  // 初始级别为1
        }
    }
    
    int max_level = 1;
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        
        for (int v : graph[u]) {
            level[v] = max(level[v], level[u] + 1);  // 更新级别
            max_level = max(max_level, level[v]);   // 记录最高级
            if (--in_degree[v] == 0) {              // 入度为0则入队
                q.push(v);
            }
        }
    }
    
    cout << max_level << endl;
    return 0;
}

注释说明:代码通过邻接表构建有向图,利用拓扑排序的依赖关系计算车站级别,核心逻辑集中在边构建和拓扑排序过程。

五、总结

该解法巧妙将“车站分级”转化为图论中的拓扑排序问题,关键在于边构建逻辑:非停靠站指向停靠站,形成依赖关系。拓扑排序保证了级别传递的正确性,时间复杂度O(n+m),适用于稀疏图场景。掌握此类转化思路对解决依赖关系类问题具有重要意义。


原创内容 转载请注明出处

分享给朋友:

相关文章

2024蓝桥杯省赛B组“传送阵”题解(C++代码+图论算法优化)

2024蓝桥杯省赛B组“传送阵”题解(C++代码+图论算法优化)

一、题目解读2024年蓝桥杯省B组“传送阵”题目要求处理一个包含n个节点的图,节点间存在单向传输关系。每个节点i可传送至a[i]指定的节点,形成可能存在的环结构。题目需求解从任意节点出发能到达的最长路...

洛谷P4551题解题报告:图论与Trie树优化异或路径问题的实战解析

洛谷P4551题解题报告:图论与Trie树优化异或路径问题的实战解析

一、题目解读洛谷P4551题要求在一个无向图中,寻找任意两点路径权值异或后的最大值。题目输入为图的边信息(点数n和n-1条边),每条边包含起点、终点及权值。需输出所有路径中权值异或的最大值。问题核心在...

1998年NOIP普及组三连击问题解析与代码详解(洛谷P1008)

1998年NOIP普及组三连击问题解析与代码详解(洛谷P1008)

一、题目解读1998年NOIP普及组三连击(洛谷P1008)要求寻找三个连续整数a、b、c(其中b=2a,c=3a),且这三个数的各位数字恰好组成1-9的排列(不重复且不包含0)。题目需输出符合条件的...

洛谷1656题解:基于Tarjan算法求解割边问题(附代码与详细步骤)

洛谷1656题解:基于Tarjan算法求解割边问题(附代码与详细步骤)

一、题目解读洛谷1656题要求在无向图中找出所有割边(即删除后导致图不连通的边)。题目核心在于判断图的连通性,并识别哪些边是“桥”。需理解图论中的连通分量概念,以及如何通过算法高效定位割边。二、解题思...

洛谷P3393题解:基于多源BFS与Dijkstra算法求解图论最小花费路径问题

洛谷P3393题解:基于多源BFS与Dijkstra算法求解图论最小花费路径问题

一、题目解读洛谷P3393题要求在一个包含N个城市和M条双向道路的图中,求解从起点1到终点N的最小花费路径。图中存在僵尸城市(僵尸无法通过)和危险城市(由僵尸城市扩散S步后标记),需要避开所有危险城市...

【NOIP提高组2003】神经网络(洛谷P1038)题解:拓扑排序与动态规划的应用

【NOIP提高组2003】神经网络(洛谷P1038)题解:拓扑排序与动态规划的应用

一、题目解读2003年NOIP提高组中的“神经网络”题目(洛谷P1038)要求处理一个由神经元和带权有向边构成的网络。题目给定神经元的初始状态、阈值,以及神经元之间的连接关系,需要模拟信号传递过程,并...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。