【置换群+贪心】51Nod1125[交换机器的最小代价]题解

来源:互联网 发布:单机游戏编程语言 编辑:程序博客网 时间:2024/05/16 05:10

题目概述

n 台重量不相同的机器,每次操作可以交换两台机器,代价是两个机器的重量之和,求使机器按照重量升序排列的最小代价。

解题报告

2017.9.30Update:神tm这是置换群不是强连通分量,我太蒟蒻了现在才知道QAQ。

对于一个位置 i ,记录 ID[i] 表示排序完毕后在位置 i 上的数(也就是第 i 小的数)原来在哪里,那么我们需要做的就是将位置 i 上的数与位置 ID[i] 上的数进行交换,使得最终在位置 i 的数归位。我们会发现按照 iID[i] 遍历,将会形成若干个置换群:

这里写图片描述

每一个置换群中,只要选一个起点,就可以使该置换群归位,根据贪心,我们肯定选最小的作为起点。

这样考虑是没有错的,但是遗漏了一种情况:从别的置换群中拿一个数 A 与当前置换群中的某一个数 B 进行交换,然后用 A 进行归位。再根据贪心, AB 我们肯定都选最小的。

从上面两种情况中取最优秀的再全部累加起来就是最优解了。

示例程序

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int maxn=50000,MAXINT=((1<<30)-1)*2+1;int n,Tot,a[maxn+5],ID[maxn+5];int M,SCC[maxn+5],num[maxn+5],MIN[maxn+5];LL ans,sum[maxn+5];bool vis[maxn+5];bool cmp(int A,int B) {return a[A]<a[B];}int main(){    freopen("program.in","r",stdin);    freopen("program.out","w",stdout);    scanf("%d",&n);M=MAXINT;    for (int i=1;i<=n;i++) scanf("%d",&a[ID[i]=i]),M=min(M,a[i]);    sort(ID+1,ID+1+n,cmp);    for (int i=1;i<=n;i++) if (!vis[i])    {        Tot++;MIN[Tot]=MAXINT;        for (int x=i;!vis[x];x=ID[x])        {            vis[x]=true;SCC[x]=Tot;            num[Tot]++;sum[Tot]+=a[x];            MIN[Tot]=min(MIN[Tot],a[x]);        }    }    for (int i=1;i<=Tot;i++)        ans+=min((LL)M*num[i]+sum[i]+M+MIN[i],(LL)MIN[i]*(num[i]-2)+sum[i]);    return printf("%lld\n",ans),0;}
原创粉丝点击