参考:http://lolita-angel.diandian.com/post/2012-10-18/40040595942
寻找一个自我置换群,然后求这个群的最小置换。
#include <stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<math.h>
#include<stack>
#define LL long long
#define maxn 20000
using namespace std;
struct list
{
int x;
int y;
}node[maxn];
int cmp(struct list a,struct list b)
{
return a.x<b.x;
}
int a[maxn];
int b[maxn];
int vis[maxn];
int main()
{
int i,n,k;
int minn;
while(~scanf("%d",&n))
{
memset(vis,0,sizeof(vis));
minn=9999999;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
minn=min(minn,a[i]);
node[i].x=a[i];
node[i].y=i;
}
sort(node+1,node+n+1,cmp);
for(i=1;i<=n;i++)b[node[i].y]=i;
LL sum=0;
LL sum1,sum2;
int mm;
for(i=1;i<=n;i++)
{
if(vis[i])continue;
if(i==b[i])continue;
sum1=sum2=0;
mm=9999999;
int j=i;
int tt;
tt=0;
while(vis[j]==0)
{
tt++;
vis[j]=1;
sum1+=a[j];
mm=min(mm,a[j]);
sum2+=a[j];
j=b[j];
}
sum1=sum1-mm+(tt-1)*mm;
sum2=mm+minn+sum2+tt*minn;
sum+=min(sum1,sum2);
}
cout<<sum<<endl;
}
return 0;
}