POJ3270 Cow Sorting【置换群】【间接排序】

题目链接:
http://poj.org/problem?id=3270

题目大意:

有N头牛,每头牛都有一个脾气值(唯一),给你N头牛的脾气值序列,可以通过交换任意

两头牛的位置,直到脾气值序列为升序,但是交换 Cow[i] 和 Cow[j] 的代价是 Cow[i] + 

Cow[j]。

问:求出将N头牛的脾气值变成升序排列所需要花费的最小代价


解题思路:

贪心思想:每次交换,我们总是希望脾气最低的那头牛与其他牛参与交换(置换),这样不断

的两两置换,由于没有重复的脾气值,则置换过程中必然会产生一个循环,这些循环构成了

一个个的置换群,对于每一个置换群,根据贪心思想:我们有两种方法交换使代价最小。

第一种:找到每个置换群里脾气最小的牛,让它和其他牛进行置换,花费代价为

Sum1 = Sum - Mina + (len-1)*Mina //化简为 Sum + (len-2)*Mina

//Sum 为置换群中所有牛的脾气和,len 为置换群的元素个数,Mina 为置换群里脾气最小

第二种:从整个牛的序列中找到脾气最小的牛,让它和置换群里的牛进行置换,最后再将置

群里脾气最小的牛 Mina 和整个序列中脾气最小的牛进行置换,花费代价为

Sum2 = Sum + Mina + (len+1)*Min;

//Sum 为置换群中所有牛的脾气,Mina为置换群中脾气最小的牛,len为置换群的元素个数,

Min 为整个序列中脾气最小的牛

比较两种情况的代价,结果加上代价小的代价值。

注:代码中用到了间接排序, 即除了 Cow[] 数组外,另开一个数组 CowNo[] 数组,初始化

小标对 CowNo[] 按照 Cow[] 数组的值升序排列,则 CowNo[] 中存放的是 Cow[] 数组第 i

个元素在整个 Cow[] 数组中是第几小的数。

比如

Cow[5]       =   2 5 7 6 4

CowNo[5]  =   1 3 5 4 2 

CowNo[2] = 3 表示 Cow[2] 在整个 Cow[] 数组中排第二小

间接排序可以在不改变原数组顺序的情况下,得到原数组的排列顺序,比较方便。


AC代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int INF = 0xffffff0;
int Cow[100100],CowNo[100100],Vis[100100];

int cmp(const int a,const int b)//间接排序的关键
{
    return Cow[a] < Cow[b];
}
int main()
{
    int n,Min,res;
    while(~scanf("%d",&n))
    {
        memset(Cow,0,sizeof(Cow));
        memset(CowNo,0,sizeof(CowNo));
        memset(Vis,0,sizeof(Vis));

        for(int i = 1; i <= n; i++)
            scanf("%d",&Cow[i]);

        Min = INF;
        for(int i = 1; i <= n; i++)
            if(Cow[i] < Min)
                Min = Cow[i];

        //下边为间接排序
        for(int i = 1; i <= n; i++)
            CowNo[i] = i;
        sort(CowNo+1,CowNo+1+n,cmp);

        res = 0;
        for(int i = 1; i <= n; i++)
        {
            if(!Vis[i])
            {
                int Start = i;

                int Mina = INF,Now = i,len = 0,Sum = 0;
                do
                {
                    Vis[Now] = 1;
                    len++;
                    Sum += Cow[Now];
                    if(Mina > Cow[Now])
                        Mina = Cow[Now];
                    Now = CowNo[Now];
                }while(Now!=Start);
                int Sum1 = Sum + (len-2)*Mina;
                int Sum2 = Sum + Mina + (len+1)*Min;
                res += min(Sum1,Sum2);
            }

        }

        printf("%d\n",res);
        //    for(int i = 1; i <= n; i++)
        //        printf("%d %d\n",Cow[i],CowNo[i]);
    }

    return 0;
}

你可能感兴趣的:(POJ3270 Cow Sorting【置换群】【间接排序】)