问题 A: 【杂题】排序

题目描述

有一列数,要对其进行排序(升序)。排序只能通过交换来实现。每次交换,可以选择这列数中的任意两个,交换他们的位置,并且交换的代价为这两个数的和。排序的总代价是排序过程中所有交换代价之和。现要求计算,对于任意给出的一列数,要将其排成升序所需的最小代价。

输入

输入包含多组数据。每组数据有两行组成。第一行一个数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;
}

猜你喜欢

转载自blog.csdn.net/Vitamin_R/article/details/83244660