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

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

1天前

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),适用于稀疏图场景。掌握此类转化思路对解决依赖关系类问题具有重要意义。


原创内容 转载请注明出处

分享给朋友:

相关文章

手搓邻接矩阵类代码注释与实现指南:从零开始理解图论数据结构(适合小白)

一、简介和特点邻接矩阵是用于表示图(Graph)的一种数据结构,通常用二维数组存储节点之间的关系。本文的graph类通过C++实现了一个基础的邻接矩阵结构,特点如下:1. 动态创建:根据用户输入的节点...

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

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

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

【力扣2846题】图论+二进制提升:高效解决连通性问题(附C++代码)

【力扣2846题】图论+二进制提升:高效解决连通性问题(附C++代码)

一、题目解读力扣2846题要求解决一个基于图连通性的操作优化问题。给定一个无向图,包含边权重,以及一系列查询,每个查询询问两点间路径的最小操作次数。题目关键在于高效计算路径上权重分布的统计信息,并转化...

【1999NOIP普及组】(洛谷P1016)旅行家的预算解题报告(附代码+注释)

【1999NOIP普及组】(洛谷P1016)旅行家的预算解题报告(附代码+注释)

一、题目解读题目要求解决旅行家从起点到终点(D1公里)的预算问题,需在沿途N个加油站中规划加油策略,使总费用最小化。每个加油站有不同油价和距离,汽车每升油可行驶D2公里,初始油量为C升,终点无加油站。...

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

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

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

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

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

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

发表评论

访客

看不清,换一张

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