基准时间限制: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; }