题目链接:https://www.luogu.com.cn/problem/P3916
题目
给出
N
N
N个点,
M
M
M条边的有向图,对于每个点
v
v
v,求
A
(
v
)
A(v)
A(v)表示从点
v
v
v出发,能到达的编号最大的点。
输出格式
第1 行,2 个整数
N
,
M
N,M
N,M。
接下来 M M M行,每行2个整数 U i , V i U_i,V_i Ui,ViU,表示边 ( U i , V i ) (U_i,V_i) (Ui,Vi)。点用 1 , 2 , ⋯ , N 1, 2,⋯,N 1,2,⋯,N编号。
输入样例:
4 3
1 2
2 4
4 3
输出样例:
4 4 3 4
说明/提示
- 对于60% 的数据, 1 ≤ N , M ≤ 1 0 3 1 ≤N,M≤ 10^3 1≤N,M≤103;
- 对于100% 的数据, 1 ≤ N , M ≤ 1 0 5 1≤N,M≤10^5 1≤N,M≤105 。
因为要求每个点能到达的最大的点,如果直接建边DFS,没有环的话也可以做(DFS搜索当前点后面的点,然后把最大的点返回回去给前面更新),但是有环会出问题,不好解决
不妨换一种思路建图,反向建边,然后DFS每次把当前点能到达的点给更新并标记即可
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int n,m;
int h[N],e[N],ne[N],cnt[N],idx;
bool vis[N];
void add(int a,int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
void dfs(int u,int res)
{
if(vis[u]) return;
vis[u] = true;
for(int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
dfs(j,res);
}
cnt[u] = res;
}
int main()
{
scanf("%d%d",&n,&m);
memset(h,-1,sizeof h);
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
add(b,a); //反向建边
}
for(int i = n; i >= 1; i--) dfs(i,i);
for(int i = 1; i <= n; i++)
{
printf("%d ",cnt[i]);
}
return 0;
}