51nod 1125[交换机器的最小代价]【贪心】

来源:互联网 发布:大数据存储技术 编辑:程序博客网 时间:2024/06/05 00:16

Description

有N台机器重量各不相等,现在要求把这些机器按照重量排序,重量从左到右依次递增。移动机器只能做交换操作,但交换机器要花费一定的费用,费用的大小就是交换机器重量的和。例如:3 2 1,交换1 3后为递增排序,总的交换代价为4。给出N台机器的重量,求将所有机器变为有序的最小代价。(机器的重量均为正整数)

题解

首先,会发现,如果我每次交换都保证某一个机器到了它最终的位置,那么我最终最多交换n1次就可以了,这样的话,我每次一定是挑最小的那个数与某一个机器交换而使另一个机器到达它自己的位置,但是,问题来了?如果最小的机器就在它自己的位置上怎么办?挑第二小的?有反例吗?

会发现,如果按照上面的原则进行交换,可以将原来的机器分成几个环,环内挑任意一个点按照上面的原则交换1次就可以使这个环全部到位。那么,由于每个机器都要参与交换至少一次,所以我们一定希望充当搬运工的那个机器是最小的,但是,这样一定是最优解吗?不一定,还有一种情况就是让环外的最小的机器充当搬运工(先与环内的最小机器交换,最后交换完以后再换回来),两种情况中的最小值就是这个环的最优解了。

代码

#include<cstdio>#include<cstring>#include<algorithm>#define maxn 50006#define LL long longusing namespace std;inline char nc(){    static char buf[100000],*i=buf,*j=buf;    return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;}inline int _read(){    char ch=nc();int sum=0;    while(!(ch>='0'&&ch<='9'))ch=nc();    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();    return sum;}struct data{    int x,id;    bool operator <(const data&c)const{return x<c.x;};}a[maxn];int n,Min,tot,id[maxn],num[maxn],mn[maxn];LL ans,w[maxn];int main(){    freopen("swap.in","r",stdin);    freopen("swap.out","w",stdout);    n=_read();Min=1e9;    for(int i=1;i<=n;i++)a[i].x=_read(),a[i].id=i,Min=min(Min,a[i].x);    sort(a+1,a+1+n);    for(int i=1;i<=n;i++) if(!id[i]){        id[i]=++tot;num[tot]++;mn[tot]=a[i].x;        while(!id[a[i].id]&&a[i].id!=i){            id[a[i].id]=tot;mn[tot]=min(mn[tot],a[a[i].id].x);num[tot]++;            w[tot]+=a[i].x+a[a[i].id].x;            swap(a[i].id,a[a[i].id].id);        }    }    for(int i=1;i<=tot;i++)ans+=min(w[i],w[i]+(LL)(num[i]-1)*(Min-mn[i])+(LL)2*(Min+mn[i]));    printf("%lld",ans);    return 0;}
阅读全文
0 0