【洛谷 P3916】图的遍历 题解(图论+深度优先搜索)-CSDN博客

60 阅读2分钟

图的遍历

题目描述

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

输入格式

第 1 1 1 行 2 2 2 个整数 N , M N,M N,M,表示点数和边数。

接下来 M M M 行,每行 2 2 2 个整数 U i , V i U_i,V_i Ui​,Vi​,表示边 ( U i , V i ) (U_i,V_i) (Ui​,Vi​)。点用 1 , 2 , … , N 1,2,\dots,N 1,2,…,N 编号。

输出格式

一行 N N N 个整数 A ( 1 ) , A ( 2 ) , … , A ( N ) A(1),A(2),\dots,A(N) A(1),A(2),…,A(N)。

样例 #1

样例输入 #1

4 3
1 2
2 4
4 3

样例输出 #1

4 4 3 4

提示

  • 对于 60 % 60\% 60% 的数据, 1 ≤ N , M ≤ 1 0 3 1 \leq N,M \leq 10^3 1≤N,M≤103。
  • 对于 100 % 100\% 100% 的数据, 1 ≤ N , M ≤ 1 0 5 1 \leq N,M \leq 10^5 1≤N,M≤105。

思路

储存图时反向存储,即将边的起点和终点对调。然后从最大编号的节点开始对图进行反向遍历,所能到达的节点的所求值即起点的值。

AC代码

#include <iostream>
#include <cstring>
using namespace std;
#define AUTHOR "HEX9CF"

const int maxn = 100005;

int cnt = 0;
int maxi[maxn];

// 链式前向星
struct Sedge
{
    int to;
    int next;
} edge[maxn];
int head[maxn];

void add(int u, int v)
{
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}

void dfs(int x, int ori)
{
    if (maxi[x])
    {
        return;
    }
    maxi[x] = ori;
    for (int i = head[x]; ~i; i = edge[i].next)
    {
        dfs(edge[i].to, ori);
    }
}

void read(int &x)
{
    char ch;
    x = 0;
    while (!('0' <= ch && '9' >= ch))
    {
        ch = getchar();
    }
    while (('0' <= ch && '9' >= ch))
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
}

int main()
{
    int n, m;
    int a, b;
    memset(head, -1, sizeof(head));
    memset(maxi, 0, sizeof(maxi));
    read(n);
    read(m);
    for (int i = 1; i <= m; i++)
    {
        read(a);
        read(b);
        add(b, a); // 反向添加边
    }
    for (int i = n; i; i--)
    {
        // 反向搜索
        dfs(i, i);
    }
    for (int i = 1; i <= n; i++)
    {
        cout << maxi[i];
        if (i != n)
        {
            cout << " ";
        }
    }
    return 0;
}