2020牛客寒假算法基础集训营6.B——图【基环树 & 记忆化dfs】

题目传送门


题目描述

现在有一个N个点的有向图,每个点仅有一条出边
你需要求出图中最长的简单路径包含点的数量
(1≤N≤1,000,000)


输入描述:

第一行一个数字N
接下来N行,每行一个正整数,第i+1行的数字表示第i个点出边终点的编号
(点从1开始标号)


输出描述:

一行一个数字,最长的简单路径的长度


输入

3
2
3
2


输出

3


题解

  • 首先这是一个基环树
  • 每个点出度都为1的有向图是一个基环内向树森林
  • 从一个点出发,一直走下去,肯定会走到一个环
  • 当走到环的时候,统计一环上的答案即可
  • 采用记忆化dfs
  • 细节见注释
    在这里插入图片描述

AC-Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn = 1e6 + 7;
const int mod = 1e9 + 7;

int to[maxn];
int vis[maxn];
int ans[maxn];
int dfs(int now) {
	vis[now] = 1;
	if (vis[to[now]]) { // 下一个点 走过
		if (ans[to[now]]) { // 同一条路径先算子节点。如果>1说明不是一条路径
			ans[now] = ans[to[now]] + 1;
		}
		else { // 走到环
			int t = now, num = 1;
			while (to[t] != now) { // 走一圈环,记录环的长度
				t = to[t];
				++num;
			}
			ans[now] = num;
			t = now;
			while (to[t] != now) { // 再走一遍环,更新环上点的答案
				t = to[t];
				ans[t] = num;
			}
		}
	}
	else {
		dfs(to[now]);
		if (!ans[now]) ans[now] = ans[to[now]] + 1;
	}
	return ans[now];
}
int main() {
	ios;
	int n;	while (cin >> n) {
		memset(vis, 0, sizeof vis);
		memset(ans, 0, sizeof ans);
		for (int i = 1; i <= n; ++i)		cin >> to[i];
		int ans = 0;
		for (int i = 1; i <= n; ++i) {
			if (!vis[i])	ans = max(ans, dfs(i));
		}
		cout << ans << endl;
	}
}
发布了196 篇原创文章 · 获赞 124 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Q_1849805767/article/details/104370790
今日推荐