题目描述
有一列数,要对其进行排序(升序)。排序只能通过交换来实现。每次交换,可以选择这列数中的任意两个,交换他们的位置,并且交换的代价为这两个数的和。排序的总代价是排序过程中所有交换代价之和。现要求计算,对于任意给出的一列数,要将其排成升序所需的最小代价。
输入
输入包含多组数据。每组数据有两行组成。第一行一个数n,表示这列数共有n个数组成。第二行n个互不相同的整数(都是小于1000的正整数),表示这列数。输入文件以n=0结尾。
输出
对于每组输入数据,输出组号和排序所需的最小代价。
样例输入
3
3 2 1
4
8 1 2 4
5
1 8 9 7 6
6
8 4 5 3 2 7
0
样例输出
Case 1: 4
Case 2: 17
Case 3: 41
Case 4: 34
( 置换群 )
// 详情题解可以参考https://www.cnblogs.com/wmrv587/p/3530506.html
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define linf 0x3f3f3f3f3f3f3f3fll
#define pi acos(-1.0)
#define ms(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
ll qpow(ll x, ll y, ll mod){ll s=1;while(y){if(y&1)s=s*x%mod;x=x*x%mod;y>>=1;}return s;}
//ll qpow(ll a, ll b){ll s=1;while(b>0){if(b%2==1)s=s*a;a=a*a;b=b>>1;}return s;
int a[1005],b[1005];
int vis[1005],id[1005];
int sum,Min,num;
void dfs(int x)
{
if(vis[x]==1) return;
sum += a[x]; num++;
Min=min(Min,a[x]);
vis[x]=1;
dfs(id[x]);
}
int main()
{
int n, cas = 1;
while(scanf("%d",&n) && n)
{
ms(vis,0);
int ans = 0;
int minn = inf;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),b[i]=a[i],
minn = min(minn,a[i]);
sort(b+1,b+1+n);
int len = unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++)
id[i]=lower_bound(b+1,b+1+len,a[i])-b;
for(int i=1; i<=n; i++)
{
if(vis[i]==0)
{
sum = num = 0;
Min=inf; dfs(i);
ans += min(Min*(num-1),minn*(num-1)+2*(Min+minn))+(sum-Min);
}
}
printf("Case %d: %d\n\n",cas++,ans);
}
return 0;
}