1. 程式人生 > >交換最少次使數列有序

交換最少次使數列有序

比較 amp targe tps 最小值 一個數 pac cas eof

問題 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

交換最少次使數列有序