51nod 1125 交换机器的最小代价

基准时间限制:1 秒 空间限制:131072 KB

有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


题解:

  一个非常神奇的贪心题目。

  首先,我们先考虑模型转化一下,考虑转化成一个图论问题,将每个位置看成一个节点,初始状态下,向位于这个节点的机器,想去的节点连边。因为每个节点只有一个想去的地方,也只有一个机器想去他,所以每个节点的出入度都为一,那么这个图就显然是由若干环组成的。

  对于每个环,我们考虑交换的策略,显然每个机器至少被交换一次,如果顺这图走,只要走一次就可以走到目标节点。但总是有机器要后退得走,离目标越来越远,反着走遍整个环才可以到达目标,为了保证最优,那么我们肯定选择重量最小的机器反着遍历整个环。然后其他点就跟这个反着遍历的机器,交换一次就可以达到目标节点。

  但还有一种最优策略,就是从别的环里面,把所有点中最小的点来换当前环最小的节点,然后再用这个最小点来遍历整个环,因为两种策略都有可能,所有要取min。

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#define MAXN 50100
#define ll long long
using namespace std;
struct node{
    int id,w;
}a[MAXN];
int n,minn;
ll ans=0;
bool b[MAXN];

bool cmp(node x,node y){
    return x.w<y.w;
}

ll dfs(int aum){
    ll sz=1,tot=a[aum].w,Min=a[aum].w,now=a[aum].id;
    b[aum]=1;
    while(now!=aum){
        b[now]=1;
        sz++;
        Min=min(Min,(ll)a[now].w);
        tot+=a[now].w;
        now=a[now].id;
    }
    return min((sz-1)*Min+tot-Min,(sz+1)*minn+tot+Min);
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i].w),a[i].id=i;
    sort(a+1,a+n+1,cmp);
    minn=a[1].w;
    for(int i=1;i<=n;i++) if(!b[i]) ans+=dfs(i);
    printf("%lld",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/renjianshige/p/7525316.html