蓝桥杯2024年第十五届省赛真题-传送阵

题目描述

小蓝在环球旅行时来到了一座古代遗迹,里面并排放置了 n 个传送阵,进入第 i 个传送阵会被传送到第 ai 个传送阵前,并且可以随时选择退出或者继续进入当前传送阵。小蓝为了探寻传送阵中的宝物,需要选择一个传送阵进入,然后连续进入之后的传送阵。小蓝希望尽可能多地进入传送门以便搜索宝物,同时他可以使用一次魔法,从某个传送阵 j 走到相邻的(第 j − 1 或第 j + 1 个)传送阵,请问小蓝最多能到达多少个不同的传送阵?一个传送阵可多次进入,但在计算答案时只算一个。

输入格式

输入的第一行包含一个正整数 n 。第二行包含 n 个正整数 a1, a2, · · · , an ,相邻整数之间使用一个空格分隔。

输出格式

输出一行包含一个整数表示答案。

样例输入

5
2 1 5 4 3

样例输出

4

提示

【样例说明】

小蓝的路径可以是:1 → 2 → 3 → 5 。其中 2 → 3 使用魔法。

【评测用例规模与约定】

对于 20% 的评测用例,1 ≤ n ≤ 1000 ;对于所有评测用例,1 ≤ n ≤ 106,且 a 是 1 至 n 的一个排列。


题目的几个重点

  • a 是 1 至 n 的一个排列

若将传送门和他的目的地连接在一起成为一个有向图,可以发现整张图构成了数个环。

  • 每次使用魔法只能进入相邻的传送阵

只有环内数据相邻的环才能在环间使用魔法。

  • 一个传送阵可多次进入

只要满足上一条的条件,即可在环间使用魔法而无需在意遍历顺序。

让我们仔细分析一下

根据上述的条件,不难得出:

  • 在环数≤2时,可以轻松地遍历所有传送门,即经过传送门数最大为传送门总数量n。
  • 在环数>2时,需要找到相邻的环,这两个相邻的环中所含传送门的数目最大。

我们需要写什么?

  • 储存环的数量和环内所含元素的容器
  • 检测两环是否相邻的函数
  • 遍历整个环的函数

由此,我们将整道题分割完毕。

完整代码

#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;
bool connected(vector<int> ring1, vector<int> ring2)
{
	for (int i = 0; i < ring1.size(); i++)
	{
		if (count(ring2.begin(), ring2.end(), ring1[i] + 1)\
			|| count(ring2.begin(), ring2.end(), ring1[i] - 1)) {
			return true;
		}
	}
	return false;
}
int getAns(vector<int> a, int n)
{
	vector<bool> vis(n + 1, false);
	vector<vector<int>> rings;
	for (int i = 1; i <= n; i++) {
		if (!vis[i]) {
			vis[i] = true;
			vector<int> thisRing;
			thisRing.push_back(i);
			int next = a[i];
			while (!vis[next]) {
				vis[next] = true;
				thisRing.push_back(next);
				next = a[next];
			}
			rings.push_back(thisRing);
		}
	}
	int ringSize = rings.size();
	if (ringSize <= 2) return n;
	int ans = 0;
	for (int i = 0; i < rings.size(); i++) {
		for (int j = i + 1; j < rings.size(); j++) {
			bool connect = connected(rings[i], rings[j]);
			if (connect) ans = max(ans, (int)(rings[i].size() + rings[j].size()));
		}
	}
	return ans;
}
int main()
{
	int t, n;
	cin >> n;
	vector<int> a;
	a.push_back(0);
	for (int i = 0; i < n; i++) {
		cin >> t;
		a.push_back(t);
	}
	int ans = getAns(a, n);
	cout << ans;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值