1. 程式人生 > >JDOJ-1008:牛排序

JDOJ-1008:牛排序

排隊 把他 交換 做的 https 一個 oid board 計算

1008: 牛排序

Time Limit: 2 Sec Memory Limit: 64 MB
Submit: 120 Solved: 52
[Submit][Status][Web Board]

Description

  農夫JOHN準備把他的 N(1 <= N <= 10,000)頭牛排隊以便於行動。因為脾氣大的牛有可能會搗亂,JOHN想把牛按脾氣的大小排序。每一頭牛的脾氣都是一個在1到100,000之間的整數並且沒有兩頭牛的脾氣值相同。在排序過程中,JOHN可以交換任意兩頭牛的位置。因為脾氣大的牛不好移動,JOHN需要X+Y秒來交換脾氣值為X和Y的兩頭牛。

  請幫JOHN計算把所有牛排好序的最短時間。

Input

  第1行: 一個數, N。

  第2~N+1行: 每行一個數,第i+1行是第i頭牛的脾氣值。

Output

  第1行: 一個數,把所有牛排好序的最短時間。

Sample Input

3 2 3 1

Sample Output

7

HINT

【樣例說明】 隊列裏有三頭牛,脾氣分別為 2,3, 1。

2 3 1 : 初始序列

2 1 3 : 交換脾氣為3和1的牛(時間=1+3=4).

1 2 3 : 交換脾氣為1和2的牛(時間=2+1=3).

總結:置換群裸題,找出每個循環,在兩種情況下去最小值,以下引自hzwer

1.找出初始狀態和目標狀態。明顯,目標狀態就是排序後的狀態。
2.畫出置換群,在裏面找循環。例如,數字是8 4 5 3 2 7
明顯,目標狀態是2 3 4 5 7 8,能寫為兩個循環:
(8 2 7)(4 3 5)。
3.觀察其中一個循環,明顯地,要使交換代價最小,應該用循環裏面最小的數字2,去與另外的兩個數字,7與8交換。這樣交換的代價是:
sum – min + (len – 1) * min
化簡後為:
sum + (len – 2) * min
其中,sum為這個循環所有數字的和,len為長度,min為這個環裏面最小的數字。

4.考慮到另外一種情況,我們可以從別的循環裏面調一個數字,進入這個循環之中,使交換代價更小。例如初始狀態:


1 8 9 7 6
可分解為兩個循環:
(1)(8 6 9 7),明顯,第二個循環為(8 6 9 7),最小的數字為6。我們可以抽調整個數列最小的數字1進入這個循環。使第二個循環變為:(8 1 9 7)。讓這個1完成任務後,再和6交換,讓6重新回到循環之後。這樣做的代價明顯是:
sum + min + (len + 1) * smallest
其中,sum為這個循環所有數字的和,len為長度,min為這個環裏面最小的數字,smallest是整個數列最小的數字。

5.因此,對一個循環的排序,其代價是sum – min + (len – 1) * min和sum + min + (len + 1) * smallest之中小的那個數字。

#include<bits/stdc++.h>

using namespace std;
const int maxn = 100005;

int pos[maxn], n, a[maxn], b[maxn], tot;
bool vis[maxn]; int cnt = 0, ans = 0, minx = 10000007;

void dfs(int now) {
    if(vis[now]) {
        ans += min(tot + (cnt - 2) * minx, tot + minx + (cnt + 1) * b[1]);
        return;
    } cnt++; tot += a[now]; vis[now] = 1; minx = min(minx, a[now]);
    dfs(pos[a[now]]);
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]), b[i] = a[i];
    sort(b + 1, b + n + 1);
    for (int i = 1; i <= n; ++i) pos[b[i]] = i;
    for (int i = 1; i <= n; ++i) {
        if(vis[i] == 0) {
            minx = 10000007; cnt = tot = 0;
            dfs(i);
        }
    } printf("%d\n", ans);
    return 0;
}

JDOJ-1008:牛排序