P3916 图的遍历
题目来源-洛谷
题意
有向图中,找出每个节点能访问到的最大的节点
思路
- 每个节点的最大节点,不是最长距离,如果是每个节点都用dfs去找最大值,显然1e6*1e6 超时了,只能60分
- 从第一个节点开始遍历,要超时,逆着思路想,求最大节点,那么从最大的节点开始遍历,逆着看哪些点能到达该节点,立刻标记,且从大的节点来看,后面的节点不可能有比该节点更大的点(哪怕有,也是被访问的-比当前更大的节点),因此只需要标记走过的节点,就可以不必再重复遍历,节省时间开销
- 因此存图时需要逆向存
数据约束
注意数组长度即可
参考代码
cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+5;
void dfs(int k,int maxk);//从节点K开始搜索
int m,n;//n个点m条边
vector<int> p[MAXN];//邻接表存图
bool f[MAXN] = {false};
int ans[MAXN] ;//存结果
int main(){
cin>>n>>m;
int x,y;
for(int i=0;i<m;i++){
cin>>x>>y; //x 能到 y
p[y].push_back(x);//反向存图
}
// 查看储存的数据是否正确
// for(int i=1;i<=n;i++){
// for(int j=0;j<p[i].size();j++){
// cout<<p[i][j]<<" ";
// }
// cout<<endl;
// }
for(int i=n;i>0;i--){
dfs(i,i) ;//从最大的点开始搜索
}
for(int i=1;i<=n;i++){
cout<<ans[i]<<" ";
}
return 0;
}
void dfs(int k,int maxk){
if(f[k]) return;
ans[k] = maxk;
f[k] = true;//如果此处不标记,但是是第一个遍历到节点就必须记得处理
for(int i=0;i<p[k].size();i++){
if(!f[p[k][i]]){ //没被访问过则访问
dfs(p[k][i],maxk);
// f[p[k][i]] = true;//在开头赋值的地方标记后就不用重复标记
}
}
return ;
}