先找置换 肯定会形成循环
如果问最小交换次数 就是n-循环数
这里问最小代价
先分成很多组置换,因为是两两交换,所以在每组置换内部,让最小的数反向走一圈,也就是 最小数交换 置换长度-1 次,其他数交换一次.还有一种可能,是引入置换外部的最小数,也就是先交换内部最小数和外部最小数,再按第一种方法搞,最后再换回来.
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=50005;
int n,a[N],vst[N],back[N];
int lst[N],pnt,maxv;
int sx[N],icnt;
ll Ans=0;
inline int Bin(int x){
return lower_bound(sx+1,sx+icnt+1,x)-sx;
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",a+i),sx[++icnt]=a[i];
sort(sx+1,sx+icnt+1);
for (int i=1;i<=n;i++) a[i]=Bin(a[i]),back[a[i]]=i;
for (int i=1;i<=n;i++)
if (!vst[i]){
pnt=0; vst[i]=i;
lst[++pnt]=sx[a[i]];
for (int j=a[i];j!=i;j=a[j])
lst[++pnt]=sx[a[j]],vst[j]=i;
if (pnt==1) continue;
ll minv=lst[1],sum=lst[1],ret,other=1;
while (vst[back[other]]==i && other<=n) other++;
for (int j=2;j<=pnt;j++)
minv=min(minv,(ll)lst[j]),sum+=lst[j];
ret=(sum-minv)+(ll)(pnt-1)*minv;
if (other<=n)
ret=min(ret,(sum-minv)+(ll)(pnt-1)*sx[other]+2LL*(sx[other]+minv));
Ans+=ret;
}
printf("%lld\n",Ans);
}