zoukankan      html  css  js  c++  java
  • POJ3270 Cow Sorting [置换]

    CowSortingCow Sorting


    Descriptionmathcal{Description}

    Farmer John有N头牛(1 ≤ N ≤ 10000),这N头牛各自有一个不同的脾气脾气指数L(1 ≤ L ≤ 100000),这N头牛按脾气指数是无序排列,指数越大的越容易破坏farmer的挤奶器,所以farmer为了保护他的设施,要对这些牛按脾气指数递增的顺序排列,但交换两头牛的代价是这两头牛的脾气指数之和,现在告诉你牛的个数N和N头牛的脾气指数Li,求最小代价


    Solutionmathcal{Solution}

    最初想法
    大小为 NN 的数列通过交换变成有序的数列, 分析样例(不妨加上两个数字).

    初态 2 3 1 5 4
    终态 1 2 3 4 5

    2211 交换, 22 到了 33 位置, 于是将 3322 交换, 22 到了 22 位置, 交换完成.

    发现 2,1,32,1,3 三者构成了一个, 同理 4,54,5 也构成了一个.

    于是得出 初步结论 : 在一个环中的数列, 可以交换 len1len-1 次, 独立到达终态 .

    :color{red}{歧路:} 然后计算出每个环花费的最小值, 累加起来得到 color{red}{错误的答案} .


    正解部分
    对于每个环, 都有一种最优的执行方案: 用环中的最小元素依次将每个元素归位, 若无外界干涉, 能取得最小值.
    但若有外界干涉, 整个数列中的 最小值 去替代中的最小值, 可能计算出的答案会更加小.
    所以计算一个环中的最小花费有两种途径:

    1. 利用环内的最小值
    2. 利用整体的最小值

    取两种中较小值, 累加进答案即可.


    实现部分
    没什么好说的.


    Codemathcal{Code}

    #include<cstdio>
    #include<algorithm>
    #define reg register
    
    const int maxn = 20005;
    const int inf = 0x7f7f7f7f;
    
    int N;
    int Ans;
    int min_v;
    int A[maxn];
    int B[maxn];
    int C[maxn];
    int tmp[maxn];
    
    bool Used[maxn];
    
    void Work(int cnt, int min_vv, int sum){
            int s_1 = sum - min_vv + (cnt-1) * min_vv;
            int s_2 = sum - min_vv + (cnt-1) * min_v + (min_v + min_vv) * 2;
            Ans += std::min(s_1, s_2);
    }
    
    int main(){
            scanf("%d", &N);
            min_v = inf;
            for(reg int i = 1; i <= N; i ++){
                    scanf("%d", &A[i]), B[i] = A[i];
                    min_v = std::min(min_v, A[i]);
            }
            std::sort(B+1, B+N+1);
            int Len = std::unique(B+1, B+N+1) - B-1;
            for(reg int i = 1; i <= N; i ++) C[i] = std::lower_bound(B+1, B+Len+1, A[i]) - B; 
            for(reg int i = 1; i <= N; i ++)
                    if(!Used[C[i]]){
                            int to = C[i], cnt = 0, min_tmp = inf, sum = 0;
                            while(!Used[to]) Used[to] = 1, sum += B[to], min_tmp = std::min(min_tmp, B[to]), to = C[to], cnt ++;
                            Work(cnt, min_tmp, sum);
                    }
            printf("%d
    ", Ans);
            return 0;
    }
    
    
  • 相关阅读:
    ORACLE函数<四>
    Oracle中的伪列<三>
    PL/SQL<八>函数
    invoice
    quite
    做人小结
    wsdl 学习笔记
    name, middle name, first name, last name
    小感叹
    qualified、quantity
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822584.html
Copyright © 2011-2022 走看看