图的遍历(图,DFS)

题目链接:https://www.luogu.com.cn/problem/P3916

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

输出格式
第1 行,2 个整数 N , M N,M N,M

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

输入样例:

4 3
1 2
2 4
4 3

输出样例:

4 4 3 4

说明/提示

  • 对于60% 的数据, 1 ≤ N , M ≤ 1 0 3 1 ≤N,M≤ 10^3 1N,M103
  • 对于100% 的数据, 1 ≤ N , M ≤ 1 0 5 1≤N,M≤10^5 1N,M105
思路:

因为要求每个点能到达的最大的点,如果直接建边DFS,没有环的话也可以做(DFS搜索当前点后面的点,然后把最大的点返回回去给前面更新),但是有环会出问题,不好解决

不妨换一种思路建图,反向建边,然后DFS每次把当前点能到达的点给更新并标记即可

AC代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 100010;

int n,m;
int h[N],e[N],ne[N],cnt[N],idx;
bool vis[N];


void add(int a,int b)
{
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx++;
}

void dfs(int u,int res)
{
    if(vis[u]) return;
    vis[u] = true;
    for(int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i];
        dfs(j,res);
    }
    cnt[u] = res;
}


int main()
{
    scanf("%d%d",&n,&m);

    memset(h,-1,sizeof h);

    while(m--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(b,a); //反向建边
    }

    for(int i = n; i >= 1; i--) dfs(i,i);

    for(int i = 1; i <= n; i++)
    {
        printf("%d ",cnt[i]);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值