置换群~
所求即为每个循环群需用的最小值之和,即min(sum - curmin+curmin*(len-1),sum + curmin + Min*(len+1));
//============================================================================
// Name : 3270.cpp
// Author :
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int a[10010], goal[10010], flag[10010], num[100010];
int curans, ans, Min, curmin, sum, len, t,com, n;
int main() {
freopen("a.txt", "r", stdin);
while(scanf("%d", &n)!=EOF){
memset(a, 0, sizeof(a));
memset(flag, 0, sizeof(flag));
memset(goal, 0, sizeof(goal));
memset(num, 0, sizeof(num));
for(int i = 0;i < n;i++){
scanf("%d", &a[i]);
goal[i] = a[i];
}
sort(goal, goal+n);
for(int i = 0;i < n;i++){
num[goal[i]] = i;
}
Min = goal[0];
ans = 0;
for(int i = 0;i < n;i++){
if(flag[i] == 1) continue;
flag[i] = 1;
if(goal[i] == a[i]){
continue;
}
com = goal[i];
sum = goal[i];
t = a[i];
curmin = goal[i];
len = 1;
while(t != com){
flag[num[t]] = 1;
sum += t;
len++;
if(t < curmin){
curmin = t;
}
t = a[num[t]];
}
curans = sum - curmin+curmin*(len-1);
if(curans > sum + curmin + Min*(len+1)){
curans = sum + curmin + Min*(len+1);
}
ans += curans;
}
printf("%d\n", ans);
}
return 0;
}