交换最少次使数列有序

问题 A: 【杂题】排序

时间限制: 1 Sec  内存限制: 128 MB

题目描述

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

输入

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


首先要明白最小交换次数的算法,大致就是n - n被分解成单循环的个数

    具体参照这个博客https://blog.csdn.net/wangxugangzy05/article/details/42454111

    然后这题就离散化一下,找出每个单循环,比较计算最小值就行了

#include<bits/stdc++.h>
using namespace std;
int n,team3[100000];
int team[100000];
int Sum,Min,Num;
int check[100000]= {0};

void f(int x)
{
    if(check[x]==1)return;

    Sum+=team[x];
    Min=min(Min,team[x]);
    Num++;
    check[x]=1;

    f(team3[x]);

}

int main()
{
    int tot=0,ans=0,all_min=INT_MAX;
    int team2[100000];
    while(scanf("%d",&n)==1)
    {
        if(n==0)return 0;
        all_min=INT_MAX;
        ans=0;
        for(int i=1; i<=n; i++)scanf("%d",&team[i]),team2[i]=team[i],all_min=min(all_min,team[i]);
        sort(team2+1,team2+1+n);
        int size=unique(team2+1,team2+1+n)-team2-1;

        for(int i=1; i<=n; i++)
            team3[i]=lower_bound(team2+1,team2+1+size,team[i])-team2;
        memset(check,0,sizeof(check));

        for(int i=1; i<=n; i++)
            if(check[i]==0)
            {
                Sum=0;
                Min=INT_MAX;
                Num=0;
                f(i);
                ans+=min(Min*(Num-1),all_min*(Num-1)+2*(Min+all_min))+(Sum-Min);
            }
        printf("Case %d: %d\n\n",++tot,ans);
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/tian-luo/p/9222318.html
今日推荐