组合数学, 置换群
分析:原交换问题相当于一个置换群,因此可以分解成s个不相交循环的并,又因为每
个循环内的交换次数一定,我们选择循环中最小的一个数与其它数交换,代价最小。进而考虑到利用所有数中最小的一个m参与其他循环中的交换可能更优,加上这一点判断,问题得以解决。
Cost = sum + Σ(i-> 1~s) min{(ki - 2)*ti, ti+ (k1+1)m};
#include <iostream>
#include <string.h>#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 10005
#define maxg 100005
int ele[maxn];
int num[maxn], n, minn;
int pos[maxg];
bool vis[maxn];
void input()
{
scanf("%d",&n);
minn = 0x1f1f1f;
for( int i = 0; i < n; i++)
{
scanf("%d",&ele[i]);
num[i] = ele[i];
if(minn > num[i])
minn = num[i];
}
}
int work( )
{
int sum = 0;
//pos[ele[i]]] 为 排序之后元素ele[i]所对应位置, 便于寻找置换群, 元素多的时候可以考虑HASH
for( int i = 0 ;i < n; i++)pos[ele[i]] = i;
//寻找置换群
for( int i = 0; i < n; i++)
{
if(!vis[i])
{
int tem = i, len = 0, minc = num[i], res = 0;
while(!vis[tem])
{
res += num[tem];
len++;
vis[tem] = 1;
minc = min(minc, num[tem]);
tem = pos[num[tem]];
}
sum = sum + res + min((len-2)*minc, minc + (len + 1) * minn);
}
}
return sum;
}
int main()
{
memset(vis, 0, sizeof(vis));
input();
sort(ele, ele + n);
printf("%d\n",work());
return 0;
}