Title Description
Given \ (N \) points, \ (M \) have edges directed graph, for each point \ (V \) , find \ (A (v) \) represents from the point \ (V \) departing , the maximum number of points can be reached.
Input and output formats
Entry
Line 1, 2 integer \ (N \) , \ (M \) .
Next \ (M \) lines, each an integer of 2 \ (U_i \) , \ (V_i \) , represents the edge ( \ (U_i \) , \ (V_i \) ). Point by \ (1,2,3 \ cdots N \) number.
Export
\ (N \) integers \ (\ $ A (. 1) \) , \ (A (2) \) , \ (\ cdots, A (N) \) .
Sample
SAMPLE INPUT
4 3
1 2
2 4
4 3
Sample Output
4 4 3 4
Thinking
Many methods of solving the problem.
Here I mention only one kind
is the Grand Master ( \ (the DFS \) ).
Can be built using the reverse side, starting with the largest point \ (DFS \)
we consider each a maximum of points from the remaining points, Let us call it \ (i \) , and all \ (i \) this point can reach the point, the point is to reach the maximum of \ (i \) .
When traversed by \ (n-\) -> \ (. 1 \) sequence
because it is descending traverse, so each point i is first encountered at this point must be reached the maximum point
on Code (away from) Music! ! !
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int dfn[maxn],low[maxn],onStack[maxn],n,m,sum,res[maxn],cnt,scc[maxn],dp[maxn];
stack<int>s;
vector<int>e[maxn];
vector<int>new_e[maxn];
struct node{
int x,y;
}edge[maxn];
void tarjan(int u){//求点u的dfn和low值
s.push(u);//入栈
onStack[u]=true;//在栈中
dfn[u]=low[u]=++cnt;//初始化
for(size_t i=0;i<e[u].size();i++){//枚举u指向的点
int next=e[u][i];
if(dfn[next]==0){//如果没访问过
tarjan(next);
low[u]=min(low[u],low[next]);
}
else if(onStack[next]==true)//访问过且在栈中,说明next跟u属于同一个scc,如果访问过但不在栈中,说明next属于别的scc
low[u]=min(low[u],low[next]);
}
if(dfn[u]==low[u]){//关键点
sum++;//scc数量加1
onStack[u]=false;//u即将出栈
scc[u]=sum;//点u所属的scc编号
res[sum]=max(res[sum],u);//更新当前scc具有的最大编号
while(s.top()!=u){
int cur=s.top();
s.pop();
onStack[cur]=false;//cur出栈
scc[cur]=sum;//记录cur 所属的scc编号
res[sum]=max(res[sum],cur);//更新当前scc具有的最大编号
}
s.pop();//弹出u
}
}
inline void dfs(int x){
if(dp[x]>0)//剪枝
return ;
dp[x]=res[x];//初始化, res[i]第i个强连通分量中的最大编号
for(size_t i=0;i<new_e[x].size();i++){//注意是新的 new_e
int next=new_e[x][i];
if(dp[next]==0)
dfs(next);
dp[x]=max(dp[x],dp[next]);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,u,v;i<=m;i++){
scanf("%d%d",&u,&v);//x指向y
edge[i].x=u;
edge[i].y=v;
e[u].push_back(v); //x的下一步的点
}
cnt=0;//时间戳初始化
for(int i=1;i<=n;i++)
if(dfn[i]==0)//没搜过
tarjan(i);
for(int i=1;i<=m;i++){
int xx=scc[edge[i].x];//找出第i条边的点u所属的scc编号
int yy=scc[edge[i].y];
if(xx!=yy)
new_e[xx].push_back(yy);//强连通分量fx指向的下一个scc是fy
}
for(int i=1;i<=sum;i++)//记忆化搜索,sum是scc的总数
if(dp[i]==0)//dp[i]记录从第i个scc出发能走到的最大编号
dfs(i);
for(int i=1;i<=n;i++)//每个点
printf("%d ",dp[scc[i]]);
return 0;
}//Excellent!!!!!