【洛谷P3916】图的遍历
今天开始着重学习图论
还是比较基础的阶段 直接看题目
P3916 图的遍历
题目描述
给出 \(N\) 个点,\(M\) 条边的有向图,对于每个点 \(v\),求 \(A(v)\) 表示从点 \(v\) 出发,能到达的编号最大的点。
输入格式
第 \(1\) 行 \(2\) 个整数 \(N,M\),表示点数和边数。
接下来 \(M\) 行,每行 \(2\) 个整数 \(U_i,V_i\),表示边 \((U_i,V_i)\)。点用 \(1,2,\dots,N\) 编号。
输出格式
一行 \(N\) 个整数 \(A(1),A(2),\dots,A(N)\)。
输入输出样例 #1
输入 #1
4 3
1 2
2 4
4 3
输出 #1
4 4 3 4
说明/提示
- 对于 \(60\%\) 的数据,\(1 \leq N,M \leq 10^3\)。
- 对于 \(100\%\) 的数据,\(1 \leq N,M \leq 10^5\)。
解法&&个人感想
看到什么一个点到多个点的题目 我们要想 这种题目是可以转化的
转化成多个点到一个点 然后反向建边
这个时候可能有人会说,诶这不是时间复杂度一样吗?
其实在这题是不一样的
我们容易看出 反向建边后从序号较大的节点DFS 如果一个节点被访问过 那么访问的起始点必定为其最大值
这个很好理解 所以在本题反向建边是避免TLE的 好像有数据卡正向建边
下面看代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,x,y,tot;
int head[100005],ver[100005],nex[100005];
int ans[100005];
void add(int x,int y){
ver[++tot]=y;
nex[tot]=head[x];
head[x]=tot;
}
void dfs(int now,int fa){
if(ans[now]) return ;
ans[now]=fa;
for(int i=head[now];i;i=nex[i]){
int y=ver[i];
dfs(y,fa);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
add(y,x);
}
for(int i=n;i>=1;i--){
if(!ans[i]) dfs(i,i);
}
for(int i=1;i<=n;i++){
cout<<ans[i]<<' ';
}
system("pause");
return 0;
}

浙公网安备 33010602011771号