• Evanyou Blog 彩带


      题目传送门

    图的遍历

    题目描述

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

    输入输出格式

    输入格式:

     

    第1 行,2 个整数 N,M 。

    接下来 M行,每行2个整数 Ui,Vi ,表示边 (Ui,Vi) 。点用 1,2,,N 编号。

     

    输出格式:

     

    N 个整数 A(1),A(2),,A(N) 。

     

    输入输出样例

    输入样例#1: 复制
    4 3
    1 2
    2 4
    4 3
    输出样例#1: 复制
    4 4 3 4

    说明

    • 对于60% 的数据,1N.K103 ;

    • 对于100% 的数据,1N,M105 。


    分析:

      一开始看到这题想到的还是Tarjan缩点+dfs,但是还有更加巧妙的方法可以更简便地AC。

      首先分析,直接搜索肯定是有错误的,因为会有环,如果数据故意卡的话是很容易卡死的(因为遍历顺序是与存边顺序有关的,而且又是有向图,直接搜可能会导致WA掉)

      当然环可以缩点去掉。但是这样太麻烦了,不如换个思路。

      因为要求的是可以到达的编号最大的点,那么我们可以反向建边,问题就转换为求可以到达该点的最大编号的点,那么就从n到1反向遍历,直接一边dfs即可。当然要注意,该图不一定是个连通图。具体看代码。

      Code:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+7;
    int n,m,head[N],size,ans[N];
    struct Node{int to,next;}edge[N];
    inline int read()
    {
        char ch=getchar();int num=0;bool flag=false;
        while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
        while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}
        return flag?-num:num;
    }
    inline void add(int x,int y)
    {
        edge[++size].to=y;
        edge[size].next=head[x];
        head[x]=size;
    }
    inline void dfs(int u,int sum)
    {
        if(ans[u])return;
        ans[u]=sum;
        for(int i=head[u];i!=-1;i=edge[i].next){
        dfs(edge[i].to,sum);}
    }
    int main()
    {
        n=read();m=read();int x,y;
        memset(head,-1,sizeof(head));
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=m;i++){
        x=read();y=read();add(y,x);}
        for(int i=n;i>=1;i--)
        if(!ans[i])dfs(i,i);
        for(int i=1;i<=n;i++)
        printf("%d ",ans[i]);
        return 0;
    }
  • 相关阅读:
    Vue cmd命令操作
    迭代器和生成器
    10-外键的变种 三种关系
    09-完整性约束
    08-数据类型(2)
    07-数据类型
    06-表的操作
    05-库的操作
    04-基本的mysql语句
    03-MySql安装和基本管理
  • 原文地址:https://www.cnblogs.com/cytus/p/9163116.html
Copyright © 2020-2023  润新知