鏈接: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;
}