洛谷P3916 图的遍历 [图论,搜索]

  题目传送门

图的遍历

题目描述

给出 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:

 1 //It is made by HolseLee on 10th June 2018
 2 //Luogu.org P3916
 3 #include<bits/stdc++.h>
 4 using namespace std;
 5 const int N=1e5+7;
 6 int n,m,head[N],size,ans[N];
 7 struct Node{int to,next;}edge[N];
 8 inline int read()
 9 {
10     char ch=getchar();int num=0;bool flag=false;
11     while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
12     while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}
13     return flag?-num:num;
14 }
15 inline void add(int x,int y)
16 {
17     edge[++size].to=y;
18     edge[size].next=head[x];
19     head[x]=size;
20 }
21 inline void dfs(int u,int sum)
22 {
23     if(ans[u])return;
24     ans[u]=sum;
25     for(int i=head[u];i!=-1;i=edge[i].next){
26     dfs(edge[i].to,sum);}
27 }
28 int main()
29 {
30     n=read();m=read();int x,y;
31     memset(head,-1,sizeof(head));
32     memset(ans,0,sizeof(ans));
33     for(int i=1;i<=m;i++){
34     x=read();y=read();add(y,x);}
35     for(int i=n;i>=1;i--)
36     if(!ans[i])dfs(i,i);
37     for(int i=1;i<=n;i++)
38     printf("%d ",ans[i]);
39     return 0;
40 }

猜你喜欢

转载自www.cnblogs.com/cytus/p/9163116.html
今日推荐