当前位置:首页 > C++知识 > 正文内容

图的遍历


【题目描述】

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

【输入】

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

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

【输出】

一行  个整数 

【输入样例】

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;
}


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

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

分享给朋友:

相关文章

STL入门——简单介绍

一、STL是什么?    STL(Standard Template Library)即标准模板库,是一个具有工业强度的,高效的C++程序库。它被容纳于C++标准程序库(C++ S...

【STL】二分查找函数(算法)—binary_search

【说明】binary_search() 实现了一个二分查找算法。它会在前两个参数指定范围内搜索等同于第三个参数的元素。指定范围的迭代器必须是正向迭代器而且元素必须可以使用 < 运算符来比较。这个...

【算法】前缀和与差分(3)二维数组前缀和

【算法】前缀和与差分(3)二维数组前缀和

0.前言前面的一篇文章,介绍了一维数组的前缀和,这篇文章中,介绍一下二维数组的前缀和1.定义二维数组的前缀和就是按照二维数组求和。公式如下:那二维前缀和中一个f[i][j]表示的意思就是以(1,1)为...

【数论】龟速乘

【数论】龟速乘

我们前面一篇文章学习了快速幂。它可以解决两类问题:a^b,(a^b)%c对于第一类,我们可以使用递归法或者迭代法可以求出,为了计算的快,我们可以引入位运算操作,但是目前来看,无论怎么优化都不能超过lo...

【数据结构】栈—表达式括号匹配

【数据结构】栈—表达式括号匹配

【题目描述】假设一个表达式有英文字母(小写)、运算符(+,—,*,/)和左右小(圆)括号构成,以“@”作为表达式的结束符。请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则返回“YES”;否则...

2023 CSP 山东地区分数线汇总

地区CSP-XCSP-JCSP-S烟台556648.5临沂516416青岛476753淄博446547.5...