【洛谷】P3916 图的遍历

洛谷P3916 图的遍历

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

输入格式
第1 行,2 个整数N,M。
接下来M行,每行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,\cdots,N 1,2,,N编号。

输出格式
N 个整数 A ( 1 ) , A ( 2 ) , ⋯   , A ( N ) A(1),A(2),\cdots,A(N) A(1),A(2),,A(N)

输入#1:

4 3
1 2
2 4
4 3

输出#1:

4 4 3 4

• 对于100% 的数据, 1 ≤ N , M ≤ 1 0 5 1 \le N , M \le 10^5 1N,M105

最原始的思路里,穷举每一个开始节点然后dfs寻找可能达到的最大的点,这样的复杂度显然是 O ( n 2 ) O(n^2) O(n2)的,估计是会超时的,想想能不能优化?

我们不如反过来思考,从大到小遍历每个点,看每个点会从哪些点到达。比如说i点被j点到达,那么之后就无需再考虑j点了,因为j点至多到达的点就是i。所以我们采取反向建图的方式:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int n,m;
vector<int> g[100010];	//反向建图
int res[100010];	//res[i]表示i能达到的最大点,最开始设置为0表示未访问过
void dfs(int now,int from){	//now表示遍历的点,from表示是尽头是from,即可以从now到达from
    res[now]=from;
    for(int k=0;k<g[now].size();k++){
        int to=g[now][k];
        if(!res[to]){
            dfs(to,from);
        }
    }
}
int main(){
    cin>>n>>m;
    while(m--){
        int u,v;
        scanf("%d %d",&u,&v);
        g[v].push_back(u);
    }
    memset(res,0,sizeof(res));
    for(int i=n;i>=1;i--){
        if(!res[i]){
            res[i]=i;
            dfs(i,i);
        }
    }
    for(int i=1;i<=n;i++) printf("%d ",res[i]);
    return 0;
}

你可能感兴趣的:(洛谷,图)