题目链接:点击打开链接
题目大意:给出你n个数,要求把这n个数排列成有序的(由小到大),每次可以交换两个数,花费是这两个数的和,现在求最小的花费
置换群的入门
求出每一个轮换的圈,对于每一个轮换中,只有在自身内交换就能完成有序,而不需要和其它轮换交叉。
一个轮换的最小值temp,轮换中有num个数,轮换的总和是sum,整个序列的最小值min1
让一个轮换花费最少有两种可能
1、轮换自身交换,轮换的最小值和其他值交换num-1次,那么花费是sum-temp+(num-1)*temp
2、用全局的最小值和轮换的最小值交换,然后执行轮换自身交换,然后再用全局最小值把轮换的最小值交换回来
sum-temp+(num-1)*min1+2*(min1+temp)
#include <cstdio> #include <cstring> #include <algorithm> using namespace std ; #define LL __int64 #define INF 0x3f3f3f3f LL a[10010] , b[10010] , id[100010] ; int vis[10010] ; int main() { int n , i , j ; LL ans = 0 , min1 , num , sum , temp ; memset(vis,0,sizeof(vis)) ; scanf("%d", &n) ; for(i = 1 , min1 = INF ; i <= n ; i++) { scanf("%d", &a[i]) ; b[i] = a[i] ; id[ a[i] ] = i ; min1 = min(min1,a[i]) ; } sort(b+1,b+n+1) ; for(i = 1 ; i <= n ; i++) { if( vis[i] || a[i] == b[i] ) continue ; j = i ; sum = num = 0 ; temp = INF ; while( !vis[ id[ b[j] ] ] ) { j = id[ b[j] ] ; sum += a[j] ; num++ ; vis[ j ] = 1 ; temp = min(temp,a[j]) ; } ans += min( sum-temp+(num-1)*temp , sum-temp+(num-1)*min1+2*(min1+temp) ) ; } printf("%I64d\n", ans) ; return 0 ; }