交换最少次使数列有序
Posted tian-luo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了交换最少次使数列有序相关的知识,希望对你有一定的参考价值。
问题 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 ",++tot,ans); } return 0; }
以上是关于交换最少次使数列有序的主要内容,如果未能解决你的问题,请参考以下文章
任意一个序列,每次可交换序列中任意两个数,最少需要多少次交换可以使序列有序?