当前位置:首页 > 牛客 > 牛客17722题解析:基于拓扑排序的安全客户识别算法及代码实现

牛客17722题解析:基于拓扑排序的安全客户识别算法及代码实现

2个月前 (07-20)

牛客17722题解析:基于拓扑排序的安全客户识别算法及代码实现 拓扑排序 图算法 牛客题解 图 有向图 邻接表 队列结构 队列 第1张

一、题目解读

牛客17722题要求识别一组客户中的“安全客户”,即不存在直接或间接依赖关系的客户。题目给定n个客户和m条依赖关系(u,v表示u依赖v),需要输出所有安全客户的编号。问题本质是判断有向图中的入度为0的节点,可通过拓扑排序解决。

二、解题思路

采用拓扑排序算法。首先构建邻接表存储,计算每个节点的出度。将出度为0的节点入队,通过拓扑排序迭代处理:每当节点出度减为0时,标记其为安全并加入队列,直至队列为空。最终输出所有安全客户编号。核心思想是利用拓扑排序的特性,逐步消除依赖关系,识别无依赖的节点。

三、解题步骤

1. 数据输入与初始化

读取n、m,构建邻接表graph,初始化出度数组out_degree和标记数组is_safe。

2. 构建图与出度计算

遍历m条边(u,v),将v加入u的邻接表,同时out_degree[u]++。

3. 拓扑排序标记安全节点

○ 初始化队列:将出度为0的节点入队并标记为安全。

○ 迭代处理:弹出队首节点u,遍历其所有指向的节点v,将v的出度减1。若v出度减为0且未标记,则标记v为安全并入队。

4. 收集安全客户

遍历is_safe数组,收集所有标记为true的节点编号。

5. 输出结果

若安全列表为空输出"None",否则按编号顺序输出。

四、代码及注释

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

vector<vector<int>> graph;  // 邻接表存储图
vector<int> out_degree;     // 出度数组
vector<bool> is_safe;       // 标记是否为安全客户

void mark_safe_customers(int n) {
    queue<int> q;
    // 初始化:出度为0的节点是安全的
    for (int i = 1; i <= n; ++i) {
        if (out_degree[i] == 0) {
            q.push(i);
            is_safe[i] = true;
        }
    }
    
    // 拓扑排序过程
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        
        // 遍历所有指向u的节点
        for (int v = 1; v <= n; ++v) {
            if (find(graph[v].begin(), graph[v].end(), u)!= graph[v].end()) {
                out_degree[v]--;
                if (out_degree[v] == 0 &&!is_safe[v]) {
                    is_safe[v] = true;
                    q.push(v);
                }
            }
        }
    }
}

int main() {
    int n, m;
    cin >> n >> m;
    
    graph.resize(n + 1);
    out_degree.resize(n + 1, 0);
    is_safe.resize(n + 1, false);
    
    // 读取边关系并构建图
    for (int i = 0; i < m; ++i) {
        int u, v;
        char comma;
        cin >> u >> comma >> v;
        graph[u].push_back(v);
        out_degree[u]++;
    }
    
    mark_safe_customers(n);
    
    // 收集所有安全客户
    vector<int> safe_list;
    for (int i = 1; i <= n; ++i) {
        if (is_safe[i]) {
            safe_list.push_back(i);
        }
    }
    
    // 输出结果
    if (safe_list.empty()) {
        cout << "None";
    } else {
        for (int i = 0; i < safe_list.size(); ++i) {
            if (i > 0) cout << " ";
            cout << safe_list[i];
        }
    }
    
    return 0;
}

五、总结

该代码通过拓扑排序高效解决了安全客户识别问题,时间复杂度为O(n+m)。关键点在于:

1. 利用出度数组快速定位初始安全节点;

2. 通过队列实现拓扑排序的动态更新;

3. 将实际问题转化为图论模型,凸显算法设计的巧妙性。

掌握拓扑排序的应用场景(如依赖关系、任务调度等)能提升解决类似问题的效率。

原创内容 转载请注明出处

分享给朋友:

相关文章

牛客13279题解:利用递归与深度优先搜索计算树的最大高度(附完整代码)

牛客13279题解:利用递归与深度优先搜索计算树的最大高度(附完整代码)

一、题目解读牛客13279题要求计算给定树的最大高度。题目输入一棵以邻接表形式表示的树(节点从0开始编号),需要输出从根节点到最深叶节点的最长路径长度。树的结构由n个节点和n-1条边构成,保证为连通无...

牛客14496题解:括号最大深度问题(栈思想与代码优化)

牛客14496题解:括号最大深度问题(栈思想与代码优化)

一、题目解读牛客14496题要求计算给定括号字符串中的最大深度。例如,对于字符串 "(()())",最大深度为2。题目考察对括号嵌套结构的理解,以及如何通过编程找到最深嵌套层次。二...

牛客NC67题解:汉诺塔递归算法与解题步骤

牛客NC67题解:汉诺塔递归算法与解题步骤

一、题目解读牛客NC67题要求解决汉诺塔问题,这是一个经典的递归算法题目。题目给定整数n,代表汉诺塔中的盘子数量,需要输出将n个盘子从起始柱移动到目标柱的所有步骤。汉诺塔问题规则为:每次只能移动一个盘...

牛客232639题解析:双指针+排序算法高效求解三角形数量(附代码详解)

牛客232639题解析:双指针+排序算法高效求解三角形数量(附代码详解)

一、题目解读牛客232639题要求计算一个整数数组中能够组成有效三角形的三边组合数量。根据三角形不等式,三边需满足任意两边之和大于第三边。例如,数组[3, 4, 5, 6]可组成两个有效三角形([3,...

洛谷P3694题解:动态规划与状态压缩优化解题全解析

洛谷P3694题解:动态规划与状态压缩优化解题全解析

一、题目解读洛谷P3694题要求解决一个多团队人数分配问题,给定n个元素和m个团队,每个元素属于一个团队,需将元素重新排列,使相邻元素属于不同团队,并最小化调整次数。题目难点在于如何高效处理团队间的空...

洛谷P1141题解:迷宫连通块问题的深度优先搜索算法与代码解析

洛谷P1141题解:迷宫连通块问题的深度优先搜索算法与代码解析

一、题目解读洛谷P1141题目要求处理一个由字符构成的迷宫,其中相同字符形成连通块,不同字符构成分隔。题目需统计连通块数量及大小,并支持查询两点是否属于同一连通块。核心在于高效识别并标记迷宫中的连通区...

发表评论

访客

看不清,换一张

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