1125 交换机器的最小代价

基准时间限制:1 秒 空间限制:131072 KB 分值: 80  难度:5级算法题
 收藏
 关注
有N台机器重量各不相等,现在要求把这些机器按照重量排序,重量从左到右依次递增。移动机器只能做交换操作,但交换机器要花费一定的费用,费用的大小就是交换机器重量的和。例如:3 2 1,交换1 3后为递增排序,总的交换代价为4。给出N台机器的重量,求将所有机器变为有序的最小代价。(机器的重量均为正整数)
Input
第1行:1个数N,表示机器及房间的数量。(2 <= N <= 50000)
第2 - N + 1行:每行1个数,表示机器的重量Wi。(1 <= Wi <= 10^9)
Output
输出最小代价。
Input示例
3
3
2
1
Output示例
4
李陶冶  (题目提供者)
C++的运行时限为:1000 ms ,空间限制为:131072 KB  示例及语言说明请按这里

题解:此题是有关置换群的内容。
1,在置换群里若有t个元素,则至少交换t-1次可以至想要的递增序列(递减序列);
2,据此题要交换代价最小,那么必须以最小的数为媒介进行交换。
3,设在置换群里t-1个元素和为sum1(就是除去了置换群中最小的数minx其他元素的和),
t个元素的和为sum,整个数列中最小的数为mins,
以置换群中最小的数minx为媒介时,要交换t-1次,说明其他t-1个元素各交换一次,
minx交换t-1次,则代价为sum1+(t-1)*minx=>sum+(t-2)*minx;
以整个数列中最小数mins为媒介时(此时置换群最小的数不是整个数列中最小的),
本就有t个元素,所以要交换t次,说明其他t个元素各交换一次,mins交换t次,
但mins不是置换群里的,所以还要交换回去,因此代价还要加mins+minx, 
则代价为sum+t*mins+mins+minx=>sum+(t+1)*mins+minx;
4,若还感觉有点不明白过程,我就举个列子,给大家模拟一遍。
eg:  7 5 2 4 6 8 1 3  a(原序列,为了方便,我将原序列命名为a,排完序的序列b)
排序后 :1 2 3 4 5 6 7 8  b
置换群有
       :7-1
        : 5-2-3-8-6
        : 4
现在以第二个置换群的最小值2为媒介对本置换群元素进行交换:
7 5 2 4  6 8 1 3(原序列,为了方便,我将原序列命名为a,排完序的序列b)
7 5 3 4 6 8 1 2 a的2下面是b的3,交换2,3; 注意:并排的序列是交换完的序列(以下类同) 
7 5 3 4 6 2 1 8  a的2下面是b的8,交换2,8 ;
7 5 3 4  2 6 1 8  a的2下面是b的6 , 交换2,6;
7 2 3 4 5 6 1 8  a的2下面是b的5,交换2,5;
第二个置换群元素都交换完毕,显然交换了4次,t本就为5,在此开来有t个元素的交换群,
至少交换t-1(其实你可以交换更多次,但没那个必要);
再交换第一个置换群的元素1,7
1 2 3 4 5 6 7 8 所有的交换完毕。

我又将1,2交换,模拟第二种代价的交换过程,其实是类似,所以就从略些;
7 5  2   4   6 8 1 3
7 5 1 4 6 8 2 3
7 5 3 4 6 821
7 5 3 4 6 1   2  8
7 5 3 41 62 8
7 1 3 4 5 6 2 8
7 2 3 4 5 6 1 8 再换回1,2,这就是为什么要在第二种的代价后再加mins+minx的原因。
1 2 3 4 5 6 7 8
由于mins+minx大小不确定,所以才比较第一种代价sum+(t-2)*minx和
第二种代价sum+(t+1)*mins+minx谁更小,就选谁。
就是说,若以mins为minx得到的代价sum+(t-2)*mins肯定小于等于sum+(t-2)*minx,
但交换mins和minx也需要代价x,所以sum+(t-2)*mins+x=>sum+(t+1)*mins+minx与
sum+(t-2)*minx大小就不确定了,进一步看谁更小,就选谁。
具体代码如下:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
struct node
{
    LL va;
    int id;
};
bool cmp (node a,node b)
{
    return a.va<b.va;
}
int main ()
{
    int n;
    node w[50005];
    LL mins=9999999,minx=9999999,a[50005];  //mins为整个数列中最小的,minx为当前置换群中最小的。
    LL sum=0;
    cin>>n;
    for (int i=0;i<n;i++)
    {
        scanf("%lld",&a[i]);
        w[i].va=a[i];
        w[i].id=i;
        sum+=a[i];
        mins=min(mins,a[i]);
    }


    sort(w,w+n,cmp);
    int f[50005]={0};
    for (int i=0;i<n;i++)
    {
        if(!f[i])
        {
            int j=i;
            int t=0;
            minx=a[j];
            while(!f[j])
            {
                t++;
                f[j]=1;
                minx=min(a[j],minx);
                j=w[j].id;//通过id去寻找置换群里的下一个元素
            }
            sum+=min((t-2)*minx,(t+1)*mins+minx);//比较这两种代价谁更小则选谁。
        }
    }
    printf("%lld",sum);
    return 0;
}
类似: poj Cow Sorting 3270(同一代码可以AC)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值