最低成本排序(C语言)

题目

N件重量为wi​(i=0,1,…,n−1)的行李排成一排。 使用机械臂对这些行李进行分类。 机器人手臂可以在一次操作中提起行李i 和行李 j并交换它们的位置,但代价是 wi​+wj​。 您可以根据需要多次操作机器人手臂。

找出按重量升序排列给定包裹行的成本的最小总和。

输入

整数 n 在第一行给出。 在第二行,给出了 n 个整数wi​(i=0,1,…,n−1),用空格分隔。

输出

在一行上输出最小值。

 约束

1≤n≤1,000

0≤wi​≤10000,wi​是所有不同的值

样例

输入:5

          1 5 3 4 2

输出:7

思路

这道题卡了我刷题的道路好久。

最终研究了大佬的博客最小成本排序 | Minimum Cost Sort | C/C++实现_重量为wi(i=0,1,…,n 1)的行李排成一排。 使用机械臂对这些行李进行分类。 机-CSDN博客学习了大佬的思路,用c语言的代码加以实现,又加了一些注释,代码如下。

这里也说一下自己的思路:

将n件货物排序好后,大佬使用的索引序列非常精妙,可以准确的找到货物的循环,通过将每个循环的货物调整好顺序就能将所有的货物都调整好顺序。

对于货物顺序的调整,循环内货物数量为1就不用调整,货物数量为2就彼此交换,货物数量为3时就需要选择“最小的”货物来帮助交换。但对于此“最小的”货物的选择会出现两种情况,一种是全部货物的最小值,虽然可以帮助减少交换代价,但是在将最小货物交换进入循环时也会带来代价;另一种是循环内货物的最小值。对于这两种情况我们选取小值采用。具体的实现过程可以看大佬博客的过程。

最终实现代码如下:

#include<stdio.h>
#include<stdlib.h>

#define MAX 1000//货物的最大数量
#define VMAX 10000//货物的最大质量

int *A,n,s;

int compare(const void *a,const void *b)
{
    return(*(int*)a-*(int*)b);
}

int solve()
{
    int ans=0;

    int *V=(int*)malloc(n*sizeof(int));
    int *B=(int*)malloc(sizeof(int)*n);//记录排序好的货物序列
    int *T=(int*)malloc(sizeof(int)*(VMAX+1));//记录排序好的货物序列的索引
    for(int i=0;i<n;i++)
    {
        B[i]=A[i];
        V[i]=0;//初始化标记数组
    }
    qsort(B,n,sizeof(int),compare);
    for(int i=0;i<n;i++)
    {
        T[B[i]]=i;
    }
    for(int i=0;i<n;i++)
    {
        if(V[i]) continue;//数组被访问过,继续下一次循环
        int cur=i;//当前货物
        int S=0;//货物的总质量
        int m=VMAX;//循环中货物的最小值
        int an=0;//记录一个循环中的货物数量
        while(1)
        {
            V[cur]=1;
            an++;
            int v=A[cur];
            m=m<v ? m : v;
            S+=v;
            cur=T[v];//更新当前索引
            if(V[cur]) break;
        }
        ans+= (S+(an-2)*m) < (m+S+(an+1)*s) ? (S+(an-2)*m) :(m+S+(an+1)*s);
    }
    free(V);
    free(B);
    free(T);
    return ans;
}

int main()
{
    scanf("%d",&n);
    A=(int*)malloc(sizeof(int)*n);
    s=VMAX;
    for(int i=0;i<n;i++)
    {
        scanf("%d",&A[i]);
        s= s<A[i]? s : A[i];
    }
    int ans=solve();
    printf("%d",ans);
    free(A);
    return 0;
}
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值