小朋友学算法(18):交换机器的最小代价

作者 : 开心源码 本文共1789个字,预计阅读时间需要5分钟 发布时间: 2022-05-12 共150人阅读

一、问题形容

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

输入
第1行:1个数N,表示机器及房间的数量。(2 <= N <= 50000)
第2 – N + 1行:每行1个数,表示机器的重量Wi。(1 <= Wi <= 10^9)

输出
最小代价

样例1输入

51 8 976

样例1输出

41

二、思路

以样例1例,先进行排序

下标12345
排序前18976
排序后16789

我们从元素1开始看,排序后元素1的位置还是1,那么就给1到1之间连一条边,形成一个自环;再到元素8,元素8排序以后到了第4个位置,而第四个位置是元素7,所以给8到7之间连一条有向边,同理连完剩下的边可以得到一张图:

1.png

那么我们可以发现两个环,那么我们回到题目中来,要使最后的总和最小,我们的贪心思路是什么?
策略一:
对于每一个环的贪心思路就是,找到这个环中最小的那个点,也就是6,而后从6开始进行交换,6和9交换,可以使9到对应的位置,花费为6+9=15,而后6和7交换,花费为6+7=13,最后等到交换完毕,自最后的答案是什么呢?就是:
(6+9)+(6+7)+(6+8) = (6+7+8+9)+6?2 = 30+12 = 42。
剩下一个环不用交换,那么当前的最小值就是42,但是这不肯定是最优解。
这种策略的解可表示为ans1 = sum + min * (cnt – 1),这里min是当前环中的最小值,cnt是min与别的元素交换的次数。

策略二:

2.png

在这个图中找到一个最小的值,而后用这个值跟着当前的环进行交换,在这个图中很显著是1,我们让第1和第二个环中的最小值6进行交换,而后再像上面一样,交换1和9,花费为:1+9=10,交换1和7,花费为:1+7=8等到交换完毕,最后的结果是:
(1+6)+(1+9)+(1+7)+(1+8)+(1+6) = (6+8+7+9)+1?5+6 = 41
这种策略的解可表示为ans2 = sum + least * (cnt + 2) + min,这里least表示所有元素的最小值,min表示当前环中的最小值。
我们的贪心策略就是在这两个策略之间,找出一个最小值ans = min(ans1, ans2)。

三、代码

#include<iostream>#include<algorithm>#define MAXN 50010using namespace std;bool visited[MAXN]; //记录该位置的机器能否已经排好序int least;//记录最小重量struct machine{    int origin;//原来的位置    int weight;//机器的重量};machine mac[MAXN];bool cmp(machine a, machine b){    return a.weight < b.weight;}long long solve(int i){    visited[i] = true;    int MIN = mac[i].weight;    long long sum = mac[i].weight;    int j = mac[i].origin;    int cnt = 0;    while(i != j)    {        sum += mac[j].weight;        MIN = min(MIN,mac[j].weight);        visited[j] = true;        j = mac[j].origin;        cnt++; //计算需要交换的机器数量    }    return sum + min((long long)MIN*(cnt-1), (long long)least*(cnt+2)+MIN);//两种策略的比较}int main(){    int n;    long long ans=0;    cin>>n;    for(int i=1;i<=n;i++)    {        cin>>mac[i].weight;        mac[i].origin=i;    }    sort(mac+1, mac+n+1, cmp);    least = mac[1].weight;    for(int i=1; i<=n; i++)    {        if(!visited[i])        {            ans += solve(i);        }    }    cout << ans << endl;    return 0;}

少儿编程、算法咨询请加微信307591841或者QQ群581357582

信息学竞赛公众号.jpg

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 小朋友学算法(18):交换机器的最小代价

发表回复