题意
有 n 个人围成若干个圈(也有可能只有一个)跳舞,每个圈至少有 2 个人。在圈中,每个人都与 2 个人相邻。特殊地,如果圈里只有 2 个人,则实际上只与一个人相邻。
现在,每个人都只记得与自己相邻的人之一,你需要给出这些人围成的圈数的最小值和最大值。
思路
最大值就是连通块数量
最小值就是把所有没有形成一个环的 全部成为一个环
没有形成环的连通块数量 是通过所有度为1的点 / 2 算出来的
在数量上相当于 最大值 - 度为1的点/2 + 1
意思是 原来有最大值cnt个点 现在需要找到最小值 也就是把所有不是环的连通块减去 之后把他们形成一个环 所以总数要+1
code
注意,为什么要用一个min(cnt,cnt - now / 2 + 1) 因为有可能所有的连通块都是环
这样得出的最小值就是 cnt + 1 甚至还没有最大值cnt个大
// https://codeforces.com/problemset/problem/1833/E 连通块+dfs
#include<iostream>
#include<cstdio>
#include<stack>
#include<vector>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<map>
#include<set>
#include<vector>
#define int long long
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define long long
#define PI acos(-1.0)
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int INF = 1e18 + 10;
const int N = 3e5 + 10;
const int M = 1e7 + 10;// 节点数量 3e6就够了是为什么?
const int mod = 1e9 + 7;
int n, m, k, ans;
int qcal(int a, int b) { int res = 1; while (b) { if (b & 1) res = res * a % mod; b >>= 1; a = a * a % mod; } return res; }
int a[N], b[N], f[N];
bool is_prime(int n) { if (n < 2) return false; for (int i = 2; i <= n / i; i++) { if (n % i == 0) { return false; } }return true; }
int du[N],p[N];
vector<bool> ve(N);
int find(int x)
{
if(x != p[x]) p[x] = find(p[x]);
return p[x];
}
void gzy()
{
cin >> n;
for(int i = 1;i <= n;i ++) p[i] = i;
for(int i = 1;i <= n;i ++)
{
cin >> a[i];
p[find(a[i])] = find(i);
}
// vector<bool> ve(n+1,false);
for(int i = 1;i <= n;i ++) ve[i] = 0,du[i] = 0;
int cnt = 0; // 最大的
for(int i = 1;i <= n;i ++)
{
if(ve[find(a[i])] == 0)
{
cnt ++;
ve[find(a[i])] = 1;
}
}
// 1 -> 2 和 2 -> 1 就不能算两次 必须是不一样的才能算
map<PII,int> mp;
for(int i = 1;i <= n;i++)
{
if(mp[{a[i],i}] != 0) continue;
du[a[i]] ++;
mp[{i,a[i]}] ++;
du[i] ++;
}
int now = 0;
for(int i = 1;i <= n;i ++)
{
if(du[i] == 1) now ++;
}
cout << min(cnt,cnt - now / 2 + 1) << ' ' << cnt << endl;
}
signed main()
{
IOS;
int _ = 1; cin >> _;
while (_--) gzy();
return 0;
}
// /**
// * ┏┓ ┏┓+ +
// * ┏┛┻━━━┛┻┓ + +
// * ┃ ┃
// * ┃ ━ ┃ ++ + + +
// * ████━████+
// * ◥██◤ ◥██◤ +
// * ┃ ┻ ┃
// * ┃ ┃ + +
// * ┗━┓ ┏━┛
// * ┃ ┃ + + + +Code is far away from
// * ┃ ┃ + bug with the animal protecting
// * ┃ ┗━━━┓ 神兽保佑,代码无bug
// * ┃ ┣┓
// * ┃ ┏┛
// * ┗┓┓┏━┳┓┏┛ + + + +
// * ┃┫┫ ┃┫┫
// * ┗┻┛ ┗┻┛+ + + +
// */