当前位置:首页 > C++目录 > 正文内容

图的遍历

亿万年的星光3个月前 (11-30)C++目录288


【题目描述】

给出  个点, 条边的有向图,对于每个点 ,求  表示从点  出发,能到达的编号最大的点。

【输入】

第  行  个整数 ,表示点数和边数。

接下来  行,每行  个整数 ,表示边 。点用  编号。

【输出】

一行  个整数 

【输入样例】

4 3
1 2
2 4
4 3

【输出样例】

4 4 3 4

【提示】

对于  的数据,

对于  的数据,



【题目分析】

题目要求对于每个点
v,找出从它出发能到达的编号最大的点。

也就是说,如果从v出发,出发可以到达点x1,x2,x3....  那么

R(v)=max(x1,x2,x3.....)

其中也包括
v 本身(因为从vv 出发至少能到达自己)。


一个常见的思路是

反向图 + 按编号从大到小 BFS


一个常见的技巧是:


  • 建反向图(即原图中的边 
    u→v 变成 
    v→u)。

  • 从编号最大的点 N 开始 BFS,在反向图中能到达的点 x,意味着在原图中 x能到达 N

  • 那么这些点的答案至少是 N

  • 然后从 N1开始,如果它还没被访问过,就 BFS,能到达的点答案至少是 N1,但注意如果之前已经赋过更大的值,就不用更新。

  • 这样按编号从大到小做 BFS,每个点只会被访问一次,因为一旦被访问,它的答案就已经确定(是当前起点的编号,并且这个编号是递减考虑的,所以第一次访问时就是最大可能值)。



算法步骤:

  1. 构建反向图 rG

  2. 初始化答案数组 ans[i] = 0

  3. 从 i = N 到 1

    • 如果 i 还没有被访问过,从 i 开始在反向图上 BFS/DFS。

    • 在 BFS 过程中,对于每个到达的点 u,如果它还没被访问过,就设置 ans[u] = i,并标记访问,加入队列。

  4. 输出 ans[1..N]


【参考答案】

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

int main() {
    int N, M;
    cin >> N >> M;

    vector<vector<int>> rG(N + 1);

    for (int i = 0; i < M; i++) {
        int u, v;
        cin >> u >> v;
        rG[v].push_back(u);
    }

    vector<int> ans(N + 1, 0);
    vector<bool> visited(N + 1, false);

    for (int i = N; i >= 1; i--) {
        if (visited[i]) continue;

        queue<int> q;
        q.push(i);
        visited[i] = true;
        ans[i] = i;

        while (!q.empty()) {
            int cur = q.front();
            q.pop();
            for (int j = 0; j < rG[cur].size(); j++) {
                int nxt = rG[cur][j];
                if (!visited[nxt]) {
                    visited[nxt] = true;
                    ans[nxt] = i;
                    q.push(nxt);
                }
            }
        }
    }

    for (int i = 1; i <= N; i++) {
        cout << ans[i];
        if (i < N) {
            cout << " ";
        }
    }
    cout << endl;

    return 0;
}


    扫描二维码推送至手机访问。

    版权声明:本文由青少年编程知识记录发布,如需转载请注明出处。

    分享给朋友:

    相关文章

    字符串的输入输出汇总

    做字符串的题目的时候,经常会遇到输入输出不对的情况,这篇文章就简单总结一下字符串常见的输入输出。2.cin基本操作:#include<iostream> #include<cstd...

    【初级篇】求最大公约数的方法

    1.辗转相除法int gcd(int a,int b)  {       if(a%b==0...

    【高级篇】C++中的sort函数详解

    【高级篇】C++中的sort函数详解

    0.简介sort函数用于C++中,对给定区间所有元素进行排序,默认为升序,也可进行降序排序。sort函数进行排序的时间复杂度为n*log2n,比冒泡之类的排序算法效率要高,sort函数包含在头文件为#...

    CSP复赛必备,时间与空间估算

    CSP复赛必备,时间与空间估算

    一、时间估算       在竞赛环境中,一般运行程序的时间是1s。这要求我们尽量不要循环太多次数,一般情况下,建议将时间复杂度控制在10^8以内。 ...

    【数据结构】队列—基本操作

    【数据结构】队列—基本操作

    一、C++实例分析       C++队列queue模板类的定义在<queue>头文件中,queue 模板类需要两个模板参数,一个是元素类型,一个容...

    C++中的输入与输出

    注:初学者只需要掌握cin、cout即可(2.2、3.2小节)1.C++输入输出概述C++的输入输出分为两大体系:1.  C++标准输入输出流(IOStream):以cin(输入流)、cou...