zoukankan      html  css  js  c++  java
  • [luogu p3916] 图的遍历

    传送门

    图的遍历

    题目描述

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

    输入输出格式

    输入格式

    第1 行,2 个整数(N,M)

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

    输出格式

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

    输入输出样例

    输入样例 #1

    4 3
    1 2
    2 4
    4 3
    

    输出样例 #1

    4 4 3 4
    

    说明

    • 对于60% 的数据,(1 le N . M le 10^3)
    • 对于100% 的数据,(1 le N , M le 10^5)

    分析

    打眼一看,如果暴力算法,时间复杂度 (operatorname{O}(n^2))

    (10^5) 这个数据量,平方算法肯定劝退了,要不然 (operatorname{O}(nlog n)) 要不然 (operatorname{O}(n))(operatorname{O}(nlog n)) 的时间复杂度算法我是没想出来,但是 (operatorname{O}(n)) 的算法可以用逆向思维思考出。

    什么是逆向思维呢?用本题举一个例子。本题让我们求每一个可以到达点编号最大的点,那么我们不仅要处理它可以到达的所有点,还要取最大值,而且一次处理只能处理一个,赔本买卖的结果就是TLE。

    那么我们就可以逆向思维,思考编号大的点可以反向到达哪些点,这样,能到达的所有点如果之前没有被到达过,那么它的值肯定就是当前点编号了,一次设置,就再也不用变了。这样我们不仅可以一次处理就处理很多点,而且没有取最大值的操作,而且如果当前点之前就被到达,可以直接return,剪枝掉很多不必要的点。这样简直赚翻了。

    具体实现过程是这样的:

    • 反向建边
    • 从N到1循环当前编号的点作为A点,并进行dfs
    • 可以dfs到的点B点中,如果B点的A值之前没有被设置,那就设置成A点的编号。如果B点的A值之前设置了,那么就直接return。(因为如果A点到C点的一条路径经过了B点,那么B点与C点就是联通的,那么既然B点被处理过了,C点也一定被处理过)
    • 处理完后,输出每个点的A值,结束程序

    上代码:

    代码

    /*
     * @Author: crab-in-the-northeast 
     * @Date: 2020-09-16 12:13:33 
     * @Last Modified by: crab-in-the-northeast
     * @Last Modified time: 2020-09-19 10:46:44
     */
    #include <iostream>
    #include <cstdio>
    #include <vector>
    
    const int maxn = 100005;
    
    int A[maxn];
    std :: vector <int> rev_side[maxn];
    
    void dfs(int u, int num) {
        A[u] = num;
        for (int i = 0; i < rev_side[u].size(); ++i) {
            int v = rev_side[u][i];
            if (!A[v])
                dfs(v, num);
        }
    }
    
    int main() {
        int n, m;
        std :: scanf("%d %d", &n, &m);
        for (int i = 1; i <= m; ++i) {
            int u, v;
            std :: scanf("%d %d", &u, &v);
            rev_side[v].push_back(u);
        }
    
        for (int i = n; i; --i) {
            if (!A[i])
                dfs(i, i);
        }
        
        for (int i = 1; i <= n; ++i)
            std :: printf("%d ", A[i]);
        putc('
    ', stdout);
        return 0;
    }
    

    评测记录

    评测记录

  • 相关阅读:
    CentOS7 防火墙firewalld详细操作
    bootstrap-datetimepicker 滚动错位问题
    Contos更换python版本
    centos7.3下使用yum 安装pip
    备注
    jenkins与SVN 问题记录
    kafka配置
    Jenkins 与github配置
    nginx File not found 错误
    nginx 总结
  • 原文地址:https://www.cnblogs.com/crab-in-the-northeast/p/luogu-p3916.html
Copyright © 2011-2022 走看看