题目
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;
}