• poj 3270 Cow Sorting 置换


      总共共10^5个数,取值在10^6之内

      离散化后与下标形成映射,转换成置换群

      然后就可以形成:

      有 n = 10^5 个位置, 每个位置有一头编号为 a[i]  (取值范围为[1,n] ) 的牛, 其愤怒值为 dep[ a[i] ]

      对于置换群求出其循环因子后. 因为置换的权值花费为 dep[i], dep[j]

      所以我们取最小的 dep, 例如循环因子 ( 1 , 4, 7, 8 ) 需要三次置换 , 我们可以取最小的 1, 其愤怒值为 dep[1] ( 我们按权值递增离散化过)

      所以三次置换分别为 ( 1, 4 ) ( 1, 7 ) ( 1, 8 )

      则三次花费为  ( dep[1] + dep[4] ) + ( dep[1] + dep[7] ) +( dep[1] + dep[8] ) 

      等价与  dep[1] * 3 + ( dep[7] + dep[8] + dep[4] )   

      我们在找循环因子时,就可以计算出 总和以及 当前循环因子的最小值.  通过 dep[ Min ] * ( num-1 ) +  ( sum(当前循环因子愤怒值总和) -  dep[Min] ) 

      其实这个思路是有问题的. 题目只要求最小花费,并未要求最小置换次数. 是否我们可能通过更多的置换得到 更少的花费呢.

      我们看这组数据:

      ( 1 , 8 , 9, 7 , 6 )   

      离散化后对应为    ,   第一列为标准序列,第二列为当前序列. 

      其循环因子为 ( 1 ) * ( 2 , 4, 3, 5 )  

      对于 循环因子 ( 2, 4 , 3, 5 )  最小置换花费为   dep[2]*3 + ( dep[3]+dep[4]+dep[5] )  = 42

      如果我们首先 把 1, 2 置换.  然后 对于 ( 1, 4, 3, 5 ) 进行置换, 之后再将 ( 1, 2 ) 置换回来总花费为  dep[1]*3 + ( dep[3]+dep[4]+dep[5] ) + 2*(dep[1]+dep[2) = 41

      根据结果我们发现这样我们可以得到一个更优的解, 那么我们需要的结果就是当前 循环因子的最小值 与 整个置换群的 最小值间的对比了

      假设当前循环因子最小dep值的下标为 p, 阶数为 n,  则 当前循环因子最优结果为

        ans =  Min (  2*( dep[1]+dep[p]  )  + dep[1]*(n-1)  ,  dep[p]*(n-1) )     +  sum( 当前循环因子愤怒值和 ) - dep[p] 

      将所有循环因子最优和累加 即为最终答案

    解题代码

    View Code
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    const int inf = 0x3fffffff;
    const int N = 1e5+7;
    typedef long long LL;
    #define MIN(a,b) (a)<(b)?(a):(b)
    
    int a[N], t[N], dep[N], n;
    int sum, cnt, Min;
    bool vis[N]; //用于标记位置
    struct node{
        int x, id;
    } p[N];
    
    bool cmp_x( node a, node b)
    {
        return a.x < b.x;
    }
    bool cmp_id(node a,node b)
    {
        return a.id < b.id;
    }
    int check( int s ){
        sum = 0; cnt = 0; Min = inf;
        for(int i = s; i < n; i++)
            if( !vis[i] ) return i;
        return -1;
    }
    int main(){
        while( scanf("%d", &n) != EOF)
        {
            for(int i = 0; i < n; i++)
            {
                scanf("%d", &( p[i].x ) );
                p[i].id = i;
            }
            sort( p, p+n, cmp_x );    
            for(int i = 0; i < n; i++)
            {    
                a[ p[i].id ] = i; // 在 id 位置上的牛 编号为 i          
                dep[i] = p[i].x;  // 编号为i的牛,愤怒值    
            }        
            sort( p, p+n, cmp_id );    
            int pos = 0;
            LL ans = 0, tmp = dep[0];
    
            memset( vis, 0, sizeof(vis));    
            while( ( pos = check( pos ) ) != -1 ){
                int s = pos; // s位置    
                while( !vis[s] ){
                    vis[s] = true;
                    cnt++; sum += dep[ a[s] ]; //记录下s位置下 坐的编号为 a[s]的牛
                    Min = MIN( Min, dep[ a[s] ] );
                    s = a[s]; //查找 a[s]位置    
                }    
                if( cnt > 1 ){ //当前循环因子数量为cnt,其最小愤怒
                    LL t1 =    1LL*(sum-Min)+1LL*Min*(cnt-1);
                    LL t2 = 1LL*(sum-Min)+ 1LL*tmp*(cnt-1)+ 2*(tmp+Min);    
                    ans += MIN( t1,t2 );    
                }        
                pos++;    
            }
            printf("%lld\n", ans);    
        }
        return 0;    
    }
  • 相关阅读:
    【python】python中的定义类属性和对像属性
    【Python】Python—判断变量的基本类型
    【python】Python中给List添加元素的4种方法分享
    【python】python各种类型转换-int,str,char,float,ord,hex,oct等
    【python】python 中的三元表达式(三目运算符)
    【python】 sort、sorted高级排序技巧
    【SQLAlchemy】SQLAlchemy技术文档(中文版)(中)
    【SQLAlchemy】SQLAlchemy技术文档(中文版)(上)
    【其他】VS提示不一致的行尾
    UML 之 用例图
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/2839677.html
Copyright © 2020-2023  润新知