pku 3270 Cow Sorting 置换群

http://poj.org/problem?id=3270

题意: 

给定N头牛的身高,要求你通过每次交换两头牛的位置使其按身高从小到大排序,身高各不相同。假设交换ai,aj两头牛的位置则花费的时间为ai + aj,求用最小的时间花费。

思路:

黑书P248详细解释。

cost += sum + Min((k – 2) * ti, ti + (k + 1) * minn);

前一个式子:sum + (k – 2) * ti,ti是所在置换群的最小值

比如:8 4 5 3 2 7

目标  2 3 4 5 7 8,里边有两个置换群(8 2 7)(4 3 5)(这里是每个置换都可以写成若干互不相交的循环的乘积(黑书P247))

第一个置换群里的ti 是2,第二里ti是3

第一个式子:置换群里要使交换代价最小,必然是每次用最小的那个和其余大的交换

最少交换次数是k – 1, 所以除了ti, 其他元素只各参加一次,所以结果是:sum + (k – 2) * ti

第二个式子: 先用ti和所有n中的最小数minn交换,让minn执行交换工作,结束后,再把minn和ti交换回来

总共交换了k + 1次,期中k – 1次是初ti的其他数和minn交换,两次是ti和minn交换

所以结果是:sum + ti + (k + 1) * minn,

比如初始是:1 8 9 7 6

目标是       1 6 7 8 9

分解为(1) (8697),第一种算出来是: 6 + 7 + 8 + 9 + (4 – 2) * 6 = 42

第二种算出来是:6 + 7 + 8 + 9 + 6 + (4 – 1) * 1 = 41 ,

第二种比第一种多交换2次,所以当ti本来就是minn时用第二种会有额外支出,所以二者取小即

总花费cost = sum + ∑min{(ki - 2)*ti,ti + (ki  + 1)*m};

ps:这学期开java课了,转变一下代码风格。

 

View Code
#include <iostream>

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <cmath>

#include <queue>

#include <stack>

#include <set>

#include <map>

#include <string>



#define CL(a,num) memset((a),(num),sizeof(a))

#define iabs(x)  ((x) > 0 ? (x) : -(x))

#define Min(a,b) (a) > (b)? (b):(a)

#define Max(a,b) (a) > (b)? (a):(b)



#define ll long long

#define inf 0x7f7f7f7f

#define MOD 100000007

#define lc l,m,rt<<1

#define rc m + 1,r,rt<<1|1

#define pi acos(-1.0)

#define test puts("<------------------->")

#define maxn 100007

#define M 100007

#define N 10007

using namespace std;

//freopen("din.txt","r",stdin);



int a[N],b[N],mp[N*100];

bool vt[N*100];

int main(){

    //freopen("din.txt","r",stdin);

    int n,i;

    scanf("%d",&n);

    int sum = 0,MIN = inf;

    for (i = 0; i < n; ++i){

        scanf("%d",&a[i]);

        sum += a[i];//求总和

        MIN = Min(a[i],MIN);//求整个序列的最小值

        b[i] = a[i];

    }

    sort(b,b + n);//b目标序列 a与b形成置换

    CL(vt,false);CL(mp,0);

    for (i = 0; i < n; ++i){

        mp[a[i]] = b[i];//置换后建立关系

    }

    for (i = 0; i < n; ++i){

        int t = a[i];

        int len = 0;

        int tMIN = inf;

        while (!vt[t]){ //找循环

            //printf("%d ",t);

            vt[t] = true;

            len++;

            tMIN = Min(tMIN,t);

            t = mp[t];

        }

        if (len > 0){

            sum += Min((len - 2)*tMIN,tMIN + (len + 1)*MIN);

        }

    }

    printf("%d\n",sum);

    return 0;

}

 

 

 

 

 

你可能感兴趣的:(sort)