1. 程式人生 > >[BZOJ1697][Usaco2007 Feb]Cow Sorting牛排序

[BZOJ1697][Usaco2007 Feb]Cow Sorting牛排序

style esp 兩種 sta 移動 pri fread 最短 ble

1697: [Usaco2007 Feb]Cow Sorting牛排序

Time Limit: 5 Sec Memory Limit: 64 MB Submit: 712 Solved: 416 [Submit][Status][Discuss]

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

輸入解釋:

隊列裏有三頭牛,脾氣分別為 2,3, 1。

Sample Output

7

輸出解釋:
2 3 1 : 初始序列
2 1 3 : 交換脾氣為3和1的牛(時間=1+3=4).
1 2 3 : 交換脾氣為1和2的牛(時間=2+1=3).
排個序找出每頭牛應該排到的位置,然後可以發現交換的牛一定是屬於同一個置換循環裏,那麽對於每個循環單獨考慮 有兩種方法搞 第一是每個元素和最小的一直換
第二種是把外面的最小的換進來再不停換,最後換回來 兩種取個最小值就行了
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; 
char buf[10000000], *ptr = buf - 1;
inline int readint(){
    int n = 0;
    char ch = *++ptr;
    while(ch < 0 || ch > 9) ch = *++ptr;
    while(ch <= 9 && ch >= 
0){ n = (n << 1) + (n << 3) + ch - 0; ch = *++ptr; } return n; } typedef long long ll; const int maxn = 10000 + 10; int num[maxn], pos[maxn], a[maxn]; bool vis[maxn] = {false}; int main(){ fread(buf, sizeof(char), sizeof(buf), stdin); int N = readint(); for(int i = 1; i <= N; i++) num[i] = a[i] = readint(); sort(a + 1, a + N + 1); for(int i = 1; i <= N; i++) pos[i] = lower_bound(a + 1, a + N + 1, num[i]) - a; ll ans = 0; for(int j, Min, tot, siz, i = 1; i <= N; i++){ if(vis[i]) continue; Min = tot = num[i]; siz = 1; vis[i] = true; j = pos[i]; while(!vis[j]){ Min = min(Min, num[j]); tot += num[j]; siz++; vis[j] = true; j = pos[j]; } ans += min((ll)Min * (siz - 2), (ll)a[1] * (siz + 1) + Min) + tot; } printf("%lld\n", ans); return 0; }

[BZOJ1697][Usaco2007 Feb]Cow Sorting牛排序