CodeForces-Round Dance

题目

看到没人用 tarjan,于是写了篇。

题面描述

\(n\) 个人围成若干个圈(也有可能只有一个)跳舞,每个圈至少有 \(2\) 个人。在圈中,每个人都与 \(2\) 个人相邻。特殊地,如果圈里只有 \(2\) 个人,则实际上只与一个人相邻。

做题思路

一道很好的题目,我们可以想到只要一个联通块满足强连通分量,那就肯定可以算一个答案,所以我们可以使用 tarjan 算法去求所有的强连通分量,这就是最大值。

然后思考最小值,很明显这道题给了提示,就是两个人成链这种情况,这种成不了环但是呢,会被 tarjan 算成一个强连通分量,我们要做的就是对所有这种情况合并即可,这种两个人是成不了环的,但是合并就行,可以合并成一个环的,这样我们就可以求最小值了。

最后就是怎么判断这种两个人成链,我们可以联想到树,既然这两个人对比别的人是独立的,那他们的深度肯定是 \(1\),因为输入只出现了一次,所以可以这样计算捏。

代码

代码简洁并且配有注释,不懂的地方可以直接评论,一小时之内答复。

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int range = 2e5 + 5;
int n;
int a[range];
vector<int>e[range];
int dfn[range];
int siz[range];
int instk[range];
int stk[range];
int scc[range];
int low[range];
int top, tot, cnt;
//以上都是tarjan要用的数组
int depth[range];//拿来判断双人成链的深度数组
//模板 tarjan 可以b站搜董晓算法有讲解的
void tarjan(int x) {
	dfn[x] = low[x] = ++tot;
	stk[++top] = x;
	instk[x] = 1;
	for (auto y : e[x]) {
		if (!dfn[y]) {
			tarjan(y);
			low[x] = min(low[x], low[y]);
		} else if (instk[y]) {
			low[x] = min(low[x], dfn[y]);
		}
	}
	if (dfn[x] == low[x]) {
		int y;
		++cnt;
		do {
			y = stk[top--];
			instk[y] = 0;
			scc[y] = cnt;
			++siz[cnt];
		} while (y != x);
	}//do while 无论如何都会进行一次 
}
void solve() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		depth[i] = 0;
		e[i].clear();
		siz[i] = 0;
		scc[i] = 0;
		dfn[i] = 0;
		instk[i] = 0;
		stk[i] = 0;
		top = cnt = tot = 0;
	}
	map<pair<int, int>, bool>ma;
	for (int i = 1, v; i <= n; i++) {
		cin >> v;
		if (!ma[ {i, v}] && !ma[ {v, i}]) {
			ma[ {i, v}] = ma[ {v, i}] = 1;
			depth[v]++;
			depth[i]++;
		}//判断重复防止多加
		e[i].push_back(v);
	}
	for (int i = 1; i <= n; i++) {
		if (!dfn[i]) {
			tarjan(i);
		}
	}
	int maxn = 0;
	for (int i = 1; i <= cnt; i++) {
		if (siz[i] > 1)maxn++;
	}
	cout << maxn << endl;
	int cnt = 0;
	for (int i = 1; i <= n; i++) {
		if (depth[i] == 1)cnt++;
	}
	cout << min(maxn, maxn - (cnt / 2) + 1) << " " << maxn << endl;
}
signed main() {
	ios::sync_with_stdio();
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while (t--)
	solve();
	return 0;


}

最后

谢谢观看。

posted @ 2025-04-16 19:57  LteShuai  阅读(11)  评论(0)    收藏  举报