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

 

 

 

 

 

转载于:https://www.cnblogs.com/E-star/archive/2012/09/03/2669456.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值