给定一个序列,每次操作可以交换两个数,花费代价为两数之和。问将该序列升序排列所需的最小代价。
以排序为型的题目可看做置换操作。
在一个循环内部的最优解是用循环中最小的数,依次与其它数进行交换,如果循环节长度为m,那么最小的数需要交换m-1次,而其它数各一次。
但是这样并不一定最优,因为有一种特殊情况,就是用循环外的一个数,与循环内的所有数交换,利用这个非常小的数进行中介。
#include <cstdio>
#include<cmath>
#include<cstring>
#include <iostream>
#include <algorithm>
typedef long long ll;
using namespace std;
struct p{
int n,ord;
};
bool cmp(p a,p b){
return a.n<b.n;
}
p a[10500];
int num[10500];
bool vis[10500];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",num+i);
a[i].n=num[i];
a[i].ord=i;
}
sort(a+1,a+n+1,cmp);
int ans=0,minn=a[1].n;
for(int i=1;i<=n;i++) if(!vis[i]){
if(num[i]==a[i].n){
vis[i]=true;
continue ;
}
int sum=0,m=1e5,j=i,cnt=0;
while(1){
cnt++;
sum+=num[j];
if(num[j]<m)
m=num[j];
vis[j]=true;
j=a[j].ord;
if(vis[j])
break;
}
ans+=min((cnt-2)*m+sum,minn+m+sum+cnt*minn);
}
cout<<ans<<endl;
return 0;
}