F-松鼠排序_2023河南萌新联赛第(一)场:河南农业大学 (nowcoder.com)
题意:给定长度为n的数组,每次可以任意交换两个元素,求将数组变为升序的最小交换次数。
一道很经典的题目了,本质上是个图论问题。我们可以遍历数组,对于每个元素,我们将该元素和它正确的位置建边,最后一定是 1 ∼ n 个环(自环也算)。对于有 k 个元素的环,最少交换次数为 k−1。假设共有 p 个环,对于第 i 个环,有 ki 个元素,则它的最少交换次数为 ki−1。因此答案为 ∑i=1p(ki−1)=n−p,即元素个数减去环的个数。
对于环的判断,运用dfs即可。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
typedef long long ll ;
const int maxv=4e6+5;
typedef pair<ll,ll> pll;
int st[N];
int cnt;
vector<int> e[N];
void dfs(int x)
{
st[x]=1;
for(auto c :e[x]){
if(!st[c]) dfs(c);
}
}
void solve()
{
int n;
cin>>n;
vector<int> a(n+5);
int cnt=0;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++){
e[a[i]].push_back(i);
}
for(int i=1;i<=n;i++){
if(!st[i]){
cnt++;
dfs(i);
}
}
cout<<n-cnt<<endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t=1;
while(t--){
solve();
}
system("pause");
return 0;
}