题意:
解法:
舔狗x指向a[x],发现可以转化为有向图。
设d[x]为点x的入度,
如果d[x]=0,那么显然优先帮x匹配最优,因为没有人是x的舔狗。
因此按照拓扑排序的方式进行匹配。
当剩下的图出现环怎么办?
那么就用并查集判断环中有多少个点,假设有cnt个点,那么匹配的人数为cnt/2*2。
code:
#include <bits/stdc++.h>
#define int long long
#define PI pair<int,int>
using namespace std;
const int maxm=2e6+5;
int pre[maxm];
int cnt[maxm];
int mark[maxm];
int d[maxm];
int a[maxm];
int n;
int ffind(int x){
return pre[x]==x?x:pre[x]=ffind(pre[x]);
}
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
d[a[i]]++;
}
queue<int>q;
for(int i=1;i<=n;i++){
if(!d[i]){
q.push(i);
}
}
int ans=0;
while(q.size()){
int x=q.front();q.pop();
if(mark[x]||mark[a[x]])continue;
mark[x]=mark[a[x]]=1;
ans+=2;
int t=a[a[x]];
d[t]--;
if(!d[t])q.push(t);
}
for(int i=1;i<=n;i++){
pre[i]=i;
cnt[i]=1;
}
for(int i=1;i<=n;i++){
if(!mark[i]&&!mark[a[i]]){
int x=ffind(i),y=ffind(a[i]);
if(x!=y){
pre[x]=y,cnt[y]+=cnt[x];
}
}
}
for(int i=1;i<=n;i++){
if(!mark[i]&&pre[i]==i){
ans+=cnt[i]/2*2;
}
}
cout<<n-ans<<endl;
}
signed main(){
ios::sync_with_stdio(0);
solve();
return 0;
}