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

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;
}

 

posted @ 2017-09-19 18:16  jzyy  阅读(222)  评论(0编辑  收藏  举报