图(基环树)

 

链接: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

 

官方题解:

这是一个简单的有关基环树的问题。
可以证明,每个点出度都为1的有向图是一个基环内向树森林。
关于这一部分的内容,可以自行查阅资料。
这里我们要用到的结论是:从一个点出发,沿着出边一路走下去,一定会走到一个环。
所以我们选择dfs,当遍历到一个已在dfs栈中的节点时,就说明找到了环,可以结束统计。
但这样是会超时的,于是我们选择带“记忆化”的dfs,从一个点开始沿着出边走下去,每当走到一个在之前某次dfs中经过的点时,就可以利用上一次的答案完成求解。
实现上有一些细节,要注意不要让复杂度退化。

 

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <iostream>
 4 #include <string>
 5 #include <math.h>
 6 #include <algorithm>
 7 #include <vector>
 8 #include <stack>
 9 #include <queue>
10 #include <set>
11 #include <map>
12 #include <sstream>
13 const int INF=0x3f3f3f3f;
14 typedef long long LL;
15 const double eps =1e-8;
16 const int mod=1e9+7;
17 const int maxn=1e6+10;
18 using namespace std;
19 
20 int to[maxn];
21 int dis[maxn];
22 int vis[maxn];
23 
24 int DFS(int u)
25 {
26     vis[u]=1;//入栈 
27     if(dis[u])//已经计算过 
28     {
29         vis[u]=0;//出栈 
30         return dis[u];
31     }
32     if(to[u]==0)//该点没有出边,好像没什么用 
33     {
34         vis[u]=0;
35         return dis[u]=1;
36     }
37     if(vis[to[u]])//遇到环 
38     {
39         int rt=to[u];//环开始的地方 
40         int v=to[rt];
41         int cnt=1;//计数 
42         while(v!=rt)//数一下这个环有几个点 
43         {
44             cnt++;
45             v=to[v];
46         }
47         dis[rt]=cnt;
48         v=to[rt];
49         while(v!=rt)//更新该环内所有的dis 
50         {
51             dis[v]=cnt;
52             v=to[v];
53         }
54         vis[u]=0;
55         return dis[u];
56     }
57     int res=DFS(to[u])+1;//递归; 
58     vis[u]=0;//出栈 
59     if(dis[u]) return dis[u];//环内计算过了,记忆化搜索 
60     else return dis[u]=res;//否则正常
61 }
62 
63 int main()
64 {
65     #ifdef DEBUG
66     freopen("sample.txt","r",stdin);
67     #endif
68     
69     int n,m; 
70     scanf("%d",&n);
71     for(int i=1;i<=n;i++)
72         scanf("%d",&to[i]);
73     int ans=0;
74     for(int i=1;i<=n;i++)
75     {
76         if(!dis[i]) DFS(i);
77         ans=max(ans,dis[i]);//求出图中最长的简单路径包含点的数量
78     }
79     printf("%d\n",ans);
80     
81     return 0;
82 }

 

 

-

 

posted @ 2020-02-16 22:47  jiamian22  阅读(342)  评论(0编辑  收藏  举报