链接:https://ac.nowcoder.com/acm/contest/3007/B
来源:牛客网
题目描述:
现在有一个N个点的有向图,每个点仅有一条出边
你需要求出图中最长的简单路径包含点的数量
(1≤N≤1,000,000)
输入描述:
第一行一个数字N
接下来N行,每行一个正整数,第i+1行的数字表示第i个点出边终点的编号
(点从1开始标号)
输出描述:
一行一个数字,最长的简单路径的长度
输入样例:
3
2
3
2
输出样例:
3
核心思想:
记忆化搜索。
注意存在环。详见代码注释。
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e6+20;
//a数组存图,dp记忆长度,vis表示第几次搜索的
//fa[i]:当点i不在环中是,fa[i]=i;
//在环中时,fa[i]表示环周长的存储位置
int a[N],dp[N],vis[N],fa[N];
struct node{
int v,z;//v表示长度,z表示环的全部长度存储的位置
node(){}
node(int vv,int zz)
{
v=vv;
z=zz;
}
};
node dfs(int x,int ci)//ci表示第几次搜索
{
//剪枝
if(vis[x]==ci) return node(0,x);//此次搜索构成了一个新环
if(vis[x]) return node(dp[fa[x]],-1);//此点被搜过
//主函数体
vis[x]=ci;//此点在第ci次被搜索
node te=dfs(a[x],ci);//继续深搜
fa[x]=(te.z==-1?x:te.z); //fa[x]赋值
dp[x]=te.v+1;//dp[x]赋值
//回溯
node re;
re.v=dp[x];
re.z=(x==te.z?-1:te.z);
return re;
}
int main()
{
int n,ans=0;
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
ans=max(ans,dfs(i,i).v);
cout<<ans<<endl;
return 0;
}