/*題意:給出一列數的初始狀態,叫你求要達到從小到大排序,至少要劃分多少工作, 工作定義:每次交換兩個
則這次操作的工作爲兩個被交換的數的和
思路:置換羣寫法:定義三個數組cow【】存儲牛的輸入,acow【】存儲目標狀態,hash【cow【】】存儲每隻牛的
初始位置 vis【】記錄有沒有被動過,接着就是找出n個裏面的輪換,計算每個輪換的長度和記錄他們之中最小值
爲了得到最優解,可以多一步操作,將n個數裏的最小值和某個輪換裏的最小值交換,讓那個最小值參與輪換,
設輪換裏的最小值爲t,n個數裏的最小值爲min,k爲輪換的長度,最後再判斷t*(k-2)和t+min*(k+1)的大小
取最小那個,所以最後的解爲:n個數的和加上:
n
k=∑ min(t*(k-2),t+min*(k+1)),所以結果爲sum+k
i=1
*/
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int cow[10010],acow[10010];//目標狀態存在acow中
int hash[100010];//存儲每隻牛的下標
bool vis[10010];//找過的牛置爲1
int main()
{
int n,i,sum,qmin,bmin;
while(scanf("%d",&n)!=EOF)
{
qmin=1<<25;
memset(vis,false,sizeof(vis));
sum=0;
for(i=0;i<n;i++)
{
scanf("%d",&cow[i]);
acow[i]=cow[i];
hash[cow[i]]=i;
sum=sum+cow[i];
if(cow[i]<qmin) qmin=cow[i];
}
sort(acow,acow+n);
int lehn=n,ans=0,leh;
while(lehn)
{
i=leh=0;
bmin=1<<25;
while(vis[i]) i++;//找到輪換的起點
int begin=i;//記錄起點,便於判斷是不是已經循環完了
while(1)
{
leh++;
vis[i]=1;
if(cow[i]<bmin) bmin=cow[i];
i=hash[acow[i]];
if(i==begin) break;
}
lehn-=leh;//長度減去輪換的長度,等於剩下的所有長度
// if(leh==1) continue;//只有一個元素的循環不需要變動
int V1=(leh-2)*bmin;
int V2=(leh+1)*qmin+bmin;
ans+=V1<V2?V1:V2;
}
printf("%d\n",ans+sum);
}
return 0;
}