题目描述
现在有一个N个点的有向图,每个点仅有一条出边
你需要求出图中最长的简单路径包含点的数量
(1≤N≤1,000,000)
输入描述:
第一行一个数字N
接下来N行,每行一个正整数,第i+1行的数字表示第i个点出边终点的编号
(点从1开始标号)
输出描述:
一行一个数字,最长的简单路径的长度
示例1
输入
复制
3
2
3
2
输出
复制
3
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 1000005;
int n;
int a[maxn],cnt[maxn],vis[maxn],dfn[maxn],sta[maxn];
int dfs(int x){
// 记忆化搜索
// 如果有记录的话,直接返回
// 否则,层层下去
if(cnt[x]) return cnt[x];
return cnt[x] = 1+dfs(a[x]);/*每一个不在环内的数,都可以递归下去,
在环内的数有长度记录,因为每一个数都肯定会递归到一个环然后结束,所以可以得出每个数的最长长度;
}
int main(void){
int i,j,k,h;
cin>>n;
for(i = 1;i<=n;++i) cin>>a[i];
for(i = 1;i<=n;++i){
if(!vis[i]){
j = i;
while(vis[j] == 0){ //此点未被访问过,记录,一直跑下去
sta[++sta[0]] = j;/*此处记录是为了方便后面的dfn[]数组清零*/
vis[j] = dfn[j] = 1;/*dfn[]用来记录是否继续下去可以成环; */
j = a[j];
}
if(dfn[j]){ // 此点访问过,说明形成一个环,计算环的长度以及将环内都赋予同一个值
k = j,h = 0;
do{
k = a[k];
++h;
}while(k != j); // 计算环长度
do{
k = a[k];
cnt[k] = h;
}while( k != j); // 将环内所有点赋予同一个长度
}
while(sta[0]){ /*将判断环的数组还原,因为如果不清零,
会直接影响到下
一次是否成环的判断*/
dfn[sta[sta[0]]] = 0;
--sta[0];
}
}
}
int ans = 0;
for(int i = 1;i<=n;++i){
ans = max(ans,dfs(i));
}
cout<<ans<<endl;
return 0;
}